home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / pcprl11.zip / MAIN.DOC < prev    next >
Text File  |  1992-02-06  |  111KB  |  3,083 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.                     A Guide to Parallel Programming
  11.  
  12.  
  13.  
  14.                                  Using
  15.  
  16.  
  17.  
  18.                  PCS-Linda and the Parallel Lan System
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.                       Parallel Computer Solutions
  34.  
  35.                            November 30, 1991
  36.  
  37.                                                                 
  38.                             Contents
  39.  
  40.  
  41.  
  42. Disclaimer:. . . . . . . . . . . . . . . . . . . . . . . . . .  4
  43.  
  44. Linda. . . . . . . . . . . . . . . . . . . . . . . . . . . . .  5
  45.      The Language Linda. . . . . . . . . . . . . . . . . . . .  5
  46.      Linda Primitives. . . . . . . . . . . . . . . . . . . . .  6
  47.      Tuples. . . . . . . . . . . . . . . . . . . . . . . . . .  6
  48.      Elements. . . . . . . . . . . . . . . . . . . . . . . . .  6
  49.      Actuals . . . . . . . . . . . . . . . . . . . . . . . . .  6
  50.      Formals . . . . . . . . . . . . . . . . . . . . . . . . .  7
  51.      Tuple Space . . . . . . . . . . . . . . . . . . . . . . .  7
  52.      Tuple Matching. . . . . . . . . . . . . . . . . . . . . .  8
  53.      Further Examples. . . . . . . . . . . . . . . . . . . . .  9
  54.      Note on real elements . . . . . . . . . . . . . . . . . .  9
  55.  
  56. Linda Instructions . . . . . . . . . . . . . . . . . . . . .   10
  57.      IN. . . . . . . . . . . . . . . . . . . . . . . . . . .   10
  58.      RD. . . . . . . . . . . . . . . . . . . . . . . . . . .   10
  59.      OUT . . . . . . . . . . . . . . . . . . . . . . . . . .   11
  60.      EVAL. . . . . . . . . . . . . . . . . . . . . . . . . .   11
  61.      INP . . . . . . . . . . . . . . . . . . . . . . . . . .   12
  62.      RDP . . . . . . . . . . . . . . . . . . . . . . . . . .   12
  63.      Hello World Example . . . . . . . . . . . . . . . . . .   12
  64.  
  65. Parallel Lan System. . . . . . . . . . . . . . . . . . . . .   14
  66.      Requirements. . . . . . . . . . . . . . . . . . . . . .   14
  67.      Packet Drivers. . . . . . . . . . . . . . . . . . . . .   15
  68.  
  69. Master . . . . . . . . . . . . . . . . . . . . . . . . . . .   17
  70.      Multiple Processor Communication. . . . . . . . . . . .   17
  71.      Different Masters . . . . . . . . . . . . . . . . . . .   18
  72.      Machine . . . . . . . . . . . . . . . . . . . . . . . .   19
  73.      DOS . . . . . . . . . . . . . . . . . . . . . . . . . .   19
  74.      Extended Memory . . . . . . . . . . . . . . . . . . . .   19
  75.      Master Installation . . . . . . . . . . . . . . . . . .   20
  76.  
  77. Worker . . . . . . . . . . . . . . . . . . . . . . . . . . .   22
  78.      Worker Installation . . . . . . . . . . . . . . . . . .   22
  79.  
  80. Developer. . . . . . . . . . . . . . . . . . . . . . . . . .   24
  81.      Compiler Directives . . . . . . . . . . . . . . . . . .   26
  82.      Units and System Code . . . . . . . . . . . . . . . . .   27
  83.      Startup Procedure . . . . . . . . . . . . . . . . . . .   27
  84.      Procedure Declarations. . . . . . . . . . . . . . . . .   30
  85.      Global Variables. . . . . . . . . . . . . . . . . . . .   30
  86.      Readln/Writeln. . . . . . . . . . . . . . . . . . . . .   30
  87.      Formal Parameters . . . . . . . . . . . . . . . . . . .   31
  88.      Nesting Procedures. . . . . . . . . . . . . . . . . . .   31
  89.      Multiple Procedures . . . . . . . . . . . . . . . . . .   31
  90.      CAUTION!. . . . . . . . . . . . . . . . . . . . . . . .   31
  91.      Developer Program Design. . . . . . . . . . . . . . . .   32
  92.      Tuning. . . . . . . . . . . . . . . . . . . . . . . . .   32
  93.      Debugging . . . . . . . . . . . . . . . . . . . . . . .   33
  94.      Main  . . . . . . . . . . . . . . . . . . . . . . . . .   33
  95.      Skeleton Code . . . . . . . . . . . . . . . . . . . . .   34
  96.      What the Developer Doesn't Show . . . . . . . . . . . .   35
  97.      RELAX!. . . . . . . . . . . . . . . . . . . . . . . . .   35
  98.  
  99. PCS-Linda. . . . . . . . . . . . . . . . . . . . . . . . . .   36
  100.      Linda Conversion Program. . . . . . . . . . . . . . . .   36
  101.      Tuple Elements. . . . . . . . . . . . . . . . . . . . .   36
  102.      Actuals - Integer/Real. . . . . . . . . . . . . . . . .   37
  103.      Integers. . . . . . . . . . . . . . . . . . . . . . . .   37
  104.      REALS . . . . . . . . . . . . . . . . . . . . . . . . .   38
  105.      Formals . . . . . . . . . . . . . . . . . . . . . . . .   38
  106.      INP & RDP . . . . . . . . . . . . . . . . . . . . . . .   38
  107.      EVAL. . . . . . . . . . . . . . . . . . . . . . . . . .   39
  108.      Tuple Size. . . . . . . . . . . . . . . . . . . . . . .   40
  109.      What Does OUT (); Produce . . . . . . . . . . . . . . .   40
  110.  
  111. An Example . . . . . . . . . . . . . . . . . . . . . . . . .   41
  112.      Analysis. . . . . . . . . . . . . . . . . . . . . . . .   43
  113.      Final Code. . . . . . . . . . . . . . . . . . . . . . .   44
  114.  
  115. Mandelbrot . . . . . . . . . . . . . . . . . . . . . . . . .   46
  116.      Graphics Screen . . . . . . . . . . . . . . . . . . . .   46
  117.      Sequential Program. . . . . . . . . . . . . . . . . . .   47
  118.      Parallel Programming Methods. . . . . . . . . . . . . .   51
  119.      Developer . . . . . . . . . . . . . . . . . . . . . . .   51
  120.      Columns . . . . . . . . . . . . . . . . . . . . . . . .   52
  121.      Results . . . . . . . . . . . . . . . . . . . . . . . .   52
  122.      Analysis. . . . . . . . . . . . . . . . . . . . . . . .   54
  123.      Worker. . . . . . . . . . . . . . . . . . . . . . . . .   55
  124.      Complete Code . . . . . . . . . . . . . . . . . . . . .   59
  125. Disclaimer:                                                     
  126.  
  127. Copyright  1991 Parallel Computer Solutions.  All Rights Reserved
  128.  
  129.  
  130.   
  131. The terms and conditions governing the sale of Parallel Computer
  132. Solutions, hardware products and the licensing of Parallel Computer
  133. Solutions, software consist solely of those set forth in the
  134. written contracts between Parallel Computer Solutions, and its
  135. customers.  No representation or other affirmation of facts
  136. contained in this publication, including but not limited to
  137. statements regarding capacity, response time, suitability for use
  138. or performance of products described herein shall be deemed to be
  139. a warranty by Parallel Computer Solutions, for any purpose or give
  140. rise to any liability by Parallel Computer Solutions, whatever.
  141.  
  142.  
  143.  
  144.  
  145. No part of this document may be copied or reproduced in any form or
  146. by any means without the prior written consent of Parallel Computer
  147. Solutions. Information is subject to change without notice.
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157. Printed in the United States of America.
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170. Linda is a registered trademark of SCIENTIFIC Computing Associates,
  171. Inc. PCS-LINDA is a trademark of Parallel Computer Solutions
  172. Parallel Lan System is a trademark of Parallel Computer Solutions
  173. Turbo Pascal is a copyright of Borland International, Inc.
  174.  
  175.                                  Linda
  176.      
  177.  
  178.      
  179.         Linda is a parallel processing coordination language.  To
  180. most computer scientists and engineers, this is a new concept. 
  181. Commonly, sequential languages such as C and Pascal are enhanced to
  182. support parallel processing; Concurrent C and Parallel Pascal are
  183. two such languages.  However, if we look at the actual code that
  184. makes up a parallel application we see that not all of the code is
  185. parallel.  It can't be.  If a parallel application was completely
  186. parallel, one instruction would be executed on each machine.  This
  187. is not reasonable of course.  Parallel programs are written such
  188. that certain pieces of code are farmed off to other processors
  189. while  other code is executed on the host machine to pull all of
  190. the pieces together.  Now there are  machines where this is not
  191. true but we will not discuss those.  These pieces of code farmed to 
  192. other processor are typically small and perform a specific
  193. operation on some data.  They are  commonly called processes.   
  194. Let's look at a common real world situation to put these ideas 
  195. together.
  196.  
  197.      Large, busy offices in a corporation usually are made up of
  198. many different people doing  some task or process.  If we were to
  199. let this office run itself, it would become a mess in a very  short
  200. time.  Some people would be doing tasks that had already been done. 
  201. There would be  miscommunication.  You can probably think of many
  202. more things that could go wrong.  What  this office needs is an
  203. office manager.  An office manager isn is responsible for pulling
  204. the  individual people into a working team.  Each team member
  205. working for the greater good of the  corporation.
  206.  
  207.  
  208. The Language Linda
  209.  
  210.      The same can be said for Linda.  Linda is a language developed
  211. at YALE University and  is copyrighted by Scientific Computing
  212. Associates, Inc.  Linda however lacks the common  features you and
  213. I commonly think of when we hear about a new language.  There are
  214. no loops,  decisions, records, etc in Linda.  All of these common
  215. functions are provided in some other  language used in conjunction
  216. with Linda.  This language could be C, Pascal, Forth or any other 
  217. language.  The primitive functions of Linda are coded in a
  218. particular language and can be used  just as any other statement
  219. can be used.  
  220.  
  221.      Linda coordinates the activities of many different executing
  222. processes on different  machines.  As we will see later, these
  223. machines do not have to be a single parallel machine such  as the
  224. Connection Machine.  The Linda system we will be using coordinates
  225. the activities of  different processes running on IBM PCs connected
  226. by an ethernet local area network.
  227.      As we describe some of the characteristics and feature of
  228. Linda, we will introduce our  version of Linda called PCS-Linda. 
  229. There are features of Linda that can be difficult to  implement on
  230. top of an existing language and compiler therefore, we have not
  231. implemented  everything  in our version.
  232.  
  233.  
  234. Linda Primitives
  235.  
  236.      It may be surprising to find out that Linda has just six
  237. instructions.  These six instructions  are in, out, rd, eval, inp,
  238. rdp.  Each of which will be discussed in detail later in this
  239. section.   First we must talk about how Linda coordinates
  240. processes.  Linda uses a distributed data structure  called a
  241. tuple.  A tuple is a data structure that can be accessed by any
  242. process thus the distributed  part.  
  243.  
  244.  
  245. Tuples
  246.  
  247.      Tuples have two parts: a name and some number of elements. 
  248. The name of a tuple is any  combination of up to sixteen
  249. characters.  The name serves as the primary matching characteristic 
  250. for the tuples.  
  251.  
  252.                     ( name, e1, e2, e3, e4, e5, e6 )
  253.  
  254.      The name can be either a variable ( string ) or enclosed in
  255. single quotes.  The elements are  filled from left to right, 
  256.  
  257.  
  258. Elements
  259.  
  260.      A tuple can have from zero to six elements.  Each of the
  261. elements will be a value or  variable of a particular type
  262. supported in the host language Linda is coded in.  In PCS-Linda the 
  263. types can be integer, real, array, and record.  Strings are not
  264. allowed in the current PCS-Linda  system.  Elements, in addition to
  265. having a specific type, can have a further description of actual 
  266. or formal.
  267.  
  268.  
  269. Actuals
  270.  
  271.      When we speak of actual, we are concerned with an actual
  272. value.  This value can be either  the numerical representation or
  273. can be contained in a variable.  When using a number as an 
  274. element, we simply state the number in one of the element fields. 
  275.  
  276.  
  277.                           ( 'example1', 1, 2 )
  278.  
  279. is an example of a tuple with name 'example1' and actuals 1 and 2,
  280. each of type integer.  If we  had two variables a and b of type
  281. integer,  
  282.  
  283.                             a, b : integer;
  284.  
  285.  
  286. and we wanted to use the values contained in these variables, we
  287. would precede each of the  variable by the & symbol.  The tuple
  288.  
  289.                          ( 'example2', &a, &b )
  290.  
  291. would be an example of a tuple with name 'example2' and actuals a
  292. and b, of type integer.  If this  tuple was used in a program, the
  293. integer values assigned to the variables a and b would be  compiled
  294. into the tuple definition.
  295.  
  296.      In addition to integers, reals or floating point values can be
  297. used as actuals.  Thus we can  have
  298.  
  299.                    ( 'example3', 3.141592, 1.2e+08 )
  300.  
  301. can also be used as a tuple.  In most cases, the only thing that
  302. differentiates an integer from a real  number is the decimal point
  303. and therefore must be included when specifying a real number.
  304.  
  305.  
  306. Formals
  307.  
  308.      Formal elements are more like variables.  They are used to
  309. collect a value from a tuple.   They are distinguishable by the
  310. lack of the & symbol.  A tuple with formal elements would  appear
  311. as
  312.  
  313.                         ( 'example4', a, b, c )
  314.  
  315.      The variables a, b, and c would be assigned to values returned
  316. after a match has taken  place on the tuple.  Formal variables can
  317. be any of the previous data types mention except strings.  
  318.  
  319.  
  320. Tuple Space
  321.  
  322.      Now that we have tuples, we have to have a place to keep them. 
  323. This storage place is  called the tuple space.  The tuple space
  324. could be envisioned as a large bag full of tuples.   
  325.      The tuple space can be likened to shared memory in that all
  326. processors have access to the  tuples in the tuple space.  However,
  327. unlike shared memory, there are no critical sections in the  tuple
  328. space.  Any of the tuples can be used by any processor at any time. 
  329. Now there are ways to  control access to the tuple space by using
  330. tuples that emulate semaphores and the like.  In order  for a
  331. process to access a tuple, a matching has to take place.  Thus a
  332. processor would sent a  template of the tuple it would like to
  333. match in the tuple space.  The machine holding the tuple  space
  334. would perform a search on all of the tuple in the tuple space.  As
  335. soon as a match is found,  the matching tuple is sent to the
  336. processor that requested the match.
  337.  
  338.      The tuple space in our system is located on a single machine
  339. called a master.  The master  is responsible for holding tuples and
  340. matching tuples.  When tuples are put into the tuple space,  the
  341. master does not check for duplicate tuples.  Any number of
  342. duplicate tuples can exist in the  tuple space.  There are specific
  343. rules that the master will follow when matching tuples. 
  344.  
  345.  
  346. Tuple Matching
  347.  
  348. RULE 1 : Tuple names must match both length and character for
  349. character.
  350.  
  351. RULE 2 : Actuals match actuals if of the same type and contain the
  352. same value.
  353.  
  354. RULE 3 : Actuals match formals if they are of the same type and
  355. length.
  356.  
  357. RULE 4 : Formals never match formals.
  358.  
  359.      Let's look at each rule using some examples.  Assume we have
  360. the following tuples in our  tuple space.  
  361.  
  362.                        ( 'stuff', row, col, 1 );
  363.  
  364.                           ( 'coord', &x, &y );
  365.  
  366.                      ( 'work', &segments, &adder );
  367.  
  368.                           ( 'Junk', 1, 3, 5 );
  369.  
  370.  
  371.   Row, col, x, y are integers;
  372.   Adder is a procedure;
  373.   Segments is a record of length 18;
  374.  
  375.  
  376.      We have to match the tuple ( 'stuff', 100, 200, start ) with
  377. a tuple in our tuple space.  First  off, RULE 1 is satisfied with
  378. the first tuple in tuple space because they both have names of
  379. length  5 and match character for character ( stuff = stuff ).  The
  380. elements of the tuples are matched next.   The tuple to be match
  381. has an actual element of type integer in the first position and
  382. value 100.   The first tuple in tuple space has a formal of type
  383. integer in the first position.  By RULE 3, the  first elements
  384. match in each of these tuples.  Further study shows that the second
  385. and third  elements match as well.
  386.  
  387.  
  388. Further Examples
  389.  
  390.      The tuple ( 'stuff', 3.4, 200, start ) does not match the
  391. tuple ( 'stuff', row, col, 1 ) because  the types of the first
  392. element are different.
  393.  
  394.      The tuple ( 'stuff', &a, &b, &start ) may or may not match the
  395. tuple ( 'stuff', row, col, 1 ).   A determination cannot be made
  396. because we do not have a value for the variable start.  If start 
  397. equals one, then we have a match but if start equals any other
  398. integer, the tuples do not match.
  399.  
  400.   
  401. Note on real elements
  402.  
  403.      As we all know, computers have a tough time representing real
  404. or floating point numbers  well.  Some numbers can be represented
  405. exactly such as 0.5 but how does a computer represent  the value of
  406. 2/3.  At some point, the computer will have to round to 0.666666667
  407. which is not  correct.  This inaccuracy must be kept in mind when
  408. using real number as element types in tuples.   If during a
  409. calculation, a real number is used in a tuple, there may not be a
  410. match because of  rounding.  Thus it is probably wise to avoid
  411. matching on reals if at all possible.  In most cases,  you will
  412. probably get a match but that one time when you don't,  keep the
  413. above in mind when  looking for the problem.
  414.  
  415.                            Linda Instructions
  416.  
  417.      Now that we have tuples and a place to put them, we must look
  418. at the individual Linda  instructions and determine what each one
  419. of them does and how to use them.  This section will be  ended with
  420. the common 'Hello World' problem coded in Linda and Pascal.  The
  421. first four Linda  instructions discussed are the most common ones
  422. used.  The last two are variants of two of the  common ones.
  423.  
  424.  
  425. IN
  426.  
  427.      The IN instruction is used to request a match on a tuple from
  428. tuple space.  The format of  the instruction is
  429.  
  430.                   IN ( name, e1, e2, e3, e4, e5, e6 )
  431.  
  432.      Only the elements necessary are included in the tuple.  The
  433. tuple specified with the IN  instruction is sent to the master for
  434. a match with a tuple in tuple space.  If there is a positive 
  435. match, the master will return the matching tuple.  If there are any
  436. formal elements, they are  assigned the appropriate values from the
  437. matching tuple.  If there is not a tuple in tuple space that 
  438. matches the tuple sent by the IN instruction, the master keeps the
  439. tuple and continually check the  tuple space for a match.  In the
  440. meantime, the processor that sent the IN instruction will block 
  441. execution until a matching tuple is sent.  Once that master has a
  442. match, it is sent.  When the  master sends the matching tuple to
  443. the requesting processor, it is permanently deleted from tuple 
  444. space.  If there are multiple copies of the same tuple in tuple
  445. space, the first one is taken.  The  master will take the first
  446. tuple that it determines matches the tuple sent with the
  447. instruction.
  448.  
  449.  
  450. RD
  451.  
  452.      The RD instruction is somewhat identical to the IN
  453. instruction.  The format of the RD is 
  454.  
  455.                   RD ( name, e1, e2, e3, e4, e5, e6 )
  456.  
  457.      The RD instruction sends a tuple to the master for a match
  458. with a tuple in tuple space.  If  the master has a match, it sends
  459. a copy of the tuple found in tuple space.  If the master does not 
  460. have a match, it will continually search tuple space for a match. 
  461. Meanwhile, the processor that  sent the RD instruction will block
  462. execution until a tuple is returned.  When the master finds a 
  463. tuple, it sends a copy of the tuple to the requesting processor. 
  464. The tuple is not deleted from tuple  space.  This allows a single
  465. tuple to be read from any processor without the overhead of INing
  466. the  tuple and OUTing the tuple just to get a copy of the tuple. 
  467. The RD instruction should be used  when communicating common data
  468. to a number of different processors.
  469.  
  470.  
  471. OUT
  472.  
  473.      We have seen how to request tuples from tuple space but how do
  474. we get tuples into tuple  space to begin with.  The OUT instruction
  475. enables us to put tuples into tuple space.  The format  of the OUT
  476. instruction is
  477.  
  478.                   out ( name, e1, e2, e3, e4, e5, e6 )
  479.  
  480.      The tuple with the OUT instruction is sent to the master and
  481. is put into tuple space.  Any  number of the same tuples can be put
  482. into tuple space.  In all cases of actuals, the actual values  are
  483. sent to the master in the tuple.  There are no pointers referencing
  484. data in a different processors  memory.  
  485.  
  486.      The master does not respond to the OUT instruction.  It is
  487. simply taken for granted the  tuple is put into tuple space.  Once
  488. an OUT has been performed, any processor can access the  tuple
  489. including the processor that issued the OUT instruction in the
  490. first place.
  491.  
  492.  
  493. EVAL
  494.  
  495.      The EVAL instruction is the most important of the Linda
  496. instruction.  Without it, the  other instructions are of no use. 
  497. The EVAL instruction is used to put code into tuple space.  This 
  498. code is picked up by workers and executed.  The format of the EVAL
  499. instruction is 
  500.  
  501.                  eval ( name, e1, e2, e3, e4, e5, e6 )
  502.  
  503.  
  504.       In PCS-Linda, the eval instruction has not been fully
  505. developed to the specification of the  original Linda EVAL.  In
  506. PCS-Linda the format of the EVAL instruction is
  507.  
  508.                       eval ( 'work', &procedure );
  509.  
  510.      All EVAL instruction must name the tuple 'work'.  Because
  511. tuple with the same name can  reside in tuple space at the same
  512. time this is not a problem.  The first element of the tuple will be 
  513. an actual designated by the & operator and the name of the
  514. procedure that is to be put into tuple  space.  So if we wanted a
  515. procedure called MANDEL to be put into tuple space to be executed, 
  516. the following instruction would be used
  517.  
  518.                        eval ( 'work', &mandel );
  519. INP
  520.  
  521.      The INP instruction is identical to the IN instruction except
  522. for one condition.  If the  master finds a tuple match when the
  523. instruction is received, it will return the tuple.  If a tuple is 
  524. not found in tuple space, the master returns a null tuple to the
  525. requestor.  Thereby allowing the  INP instruction to be evaluated
  526. as either true or false depending on whether or not a tuple was 
  527. matched from tuple space.  PCS-Linda implementation information of
  528. this instruction will be  given later.
  529.  
  530.  
  531. RDP
  532.  
  533.      The RDP instruction is identical to the RD instruction except
  534. the master does not  continually search for a match if its first
  535. attempt in unsuccessful.  If a tuple is found, the  matching tuple
  536. is returned to the requestor.  If the master does not find a
  537. matching tuple in tuple  space, the master will return null.  Thus
  538. allowing the RDP instruction to be evaluated as either  true of
  539. false depending on whether or not a tuple is returned.
  540.  
  541.         Those are the six instructions that make up the Linda
  542. coordination language.  Let's look at an example of a 'Hello World'
  543. program using Linda and Pascal.
  544.  
  545.  
  546. Hello World Example
  547.  
  548.      We will assume we are working on a system with 8 worker
  549. processors.  The beginning of  our program would be standard
  550. Pascal.
  551.  
  552.                     program hello;
  553.  
  554.                     const
  555.                       num_proc = 8;
  556.  
  557. Next we have to write the procedure for the workers.
  558.  
  559.                     procedure world;
  560.                     var
  561.                       count : integer;
  562.  
  563.                     begin
  564.  
  565.                       in ( 'count', count )
  566.                       inc ( count );
  567.                       out ( 'count', &count
  568.                       out ( 'hello', &count );
  569.  
  570.                     end;
  571.   Now the main procedure.
  572.                     begin
  573.  
  574.                       out ( 'count', 0 );
  575.                       for i := 1 to num_proc do
  576.                         eval ( 'work', &world );
  577.  
  578.                       for i := 1 to num_proc do
  579.                         begin
  580.                           in ( 'hello', proc );
  581.                           writeln ( 'Hello from processor', proc ); 
  582.                        end;
  583.                       in ( 'count', 8 );
  584.  
  585.                     end;
  586.  
  587.  
  588.      The program begins with the tuple called COUNT being put into
  589. tuple space with an  integer actual of 0.  This is followed by
  590. eight copies of the WORLD procedure; one for each  worker.  The
  591. main program goes into a loop requesting a HELLO tuple one at a
  592. time.  Not that  the first element is a formal, thus we are only
  593. matching on the name of the tuple HELLO.  The  formal element will
  594. have some value on each loop iteration.  The numbers my not be in
  595. order.   As each tuple is found in tuple space, a message is
  596. printed that says Hello from processor -.  The  code ends with an
  597. IN which cleans up the tuple space.
  598.  
  599.      The workers are instructed to IN the COUNT tuple, increment
  600. the number it finds in the  first element position and put the
  601. tuple back in tuple space for the next processor.  After it does 
  602. this, it puts a tuple in tuple space called HELLO with the number
  603. it put into the COUNT tuple.   Each worker will get a different
  604. number to report back to the main code.
  605.  
  606.      Now as we stated above, this code will receive eight tuple
  607. with the name HELLO is any  order.  If we changed the main programs
  608. loop slightly, we could guarantee to get the HELLO  tuple in order
  609. from 1 to 8.
  610.  
  611.                     for i := 1 to 8 do
  612.                       begin
  613.                         in ( 'hello', &i );
  614.                         writeln ( 'Hello from process - ', i );   
  615.                    end;
  616.  
  617.      We have changed the first element from a formal to an actual. 
  618. Thus instead of the master  having to match the name, it must match
  619. the first element as well.  Therefore, the it will return a  HELLO
  620. tuple only when the first element is a 1.
  621.  
  622.                           Parallel Lan System
  623.  
  624.  
  625.      
  626.      Now that we know how to program Linda and we have seen a
  627. parallel program, we need  to begin doing some real work.  So now
  628. we can sit down to our PC and begin programming the  examples.  
  629.  
  630.      Well not exactly.  Our common PC is a single processor
  631. machine.  We have no way of  dividing up work and allowing
  632. different processors to work on the pieces.  We have two options. 
  633.  We can purchase an expensive parallel machine for several
  634. thousands of dollars.  Have it installed  and teach ourselves the
  635. things necessary to program the machine.  Or we can use the
  636. Parallel Lan  System.
  637.  
  638.      The Parallel Lan System is a software package that allows IBM
  639. PC or compatible  machines to operate as a parallel processor.  The
  640. machines must be connected together by an  ethernet local area
  641. network.  A minimum system consists of three machines: a master,
  642. worker,  and a developer.
  643.  
  644.      Using Turbo Pascal and the Parallel Lan System ( PLS ), a
  645. parallel program can be  constructed for any parallel algorithm we
  646. so desire.  In addition, we have a  version of Linda  called PCS-
  647. Linda that we will use to coordinate the activities of the
  648. different processes created  our the parallel program.  
  649.  
  650.      The PLS was created to co-exist with other network products on
  651. the market such as  Novell Netware and DECNet.  The system will not
  652. interfere with NCSA or PCSA or any of the  TCP/IP programs.  The
  653. Parallel Lan System can even be configured to run several parallel 
  654. programs on the same network sharing the same processor of the
  655. system.  
  656.  
  657.  
  658. Configuration
  659.  
  660.      The configuration of the Parallel Lan System is very important
  661. to the efficiency of the  parallel system.  The remaining sections
  662. will document the different components of the PLS.   Several
  663. examples will be presented in the end of the guide.
  664.  
  665.  
  666. Requirements
  667.  
  668.      The Parallel Lan System operates by using an ethernet local
  669. area network ( LAN ).  LANs  are very popular among educational
  670. instructions and businesses.  Various packages are available  to
  671. run on networks including Novell Netware and MS Lan Manager.
  672.  
  673.      The Parallel Lan System communicates on an ethernet by way of
  674. a packet driver.  Most  ethernet card manufacturers have these
  675. drivers available at no cost.  In addition, there are public 
  676. domain packet drivers available for most cards.  
  677.  
  678.  
  679. Packet Drivers
  680.  
  681.      Packet drivers are terminate and stay-resident ( TSR )
  682. programs which act as an interface  between a developer and an
  683. ethernet card.  Ethernet cards use a hardware interrupt of a PC.  
  684. When this interrupt is activated, the packet driver code is
  685. activated to perform some function.   Likewise, the Parallel Lan
  686. System software is able to activate a software interrupt which also 
  687. activates the packet driver code for its own use.  Software can be
  688. written that locates the packet  driver installed in a machine thus
  689. allowing an PC and ethernet card to be used without changing  the
  690. system software.
  691.  
  692.      Manufactures who provide packet drivers will also include
  693. information on how to install  them.  Packet drivers can be used
  694. with most network packages.  An advantage of using packet  driver
  695. is multiple applications can access the same ethernet card.  The
  696. packet driver has the  ability to give a packet from the LAN to one
  697. application or another based on a type field located  in the
  698. packet.
  699.  
  700.      What we want to do now is install the packet drivers for the
  701. machines the system will run  on.  Follow the instructions given by
  702. the manufacturer. With that, we want to verify that  everything to
  703. this point is operating correctly.  On the disk labeled system
  704. software is a file called  PKTINFO.EXE.  When executed, this
  705. program will give us information about the ethernet card  and
  706. packet driver installed on a particular machine.  After the packet
  707. driver has been installed in a  machine, place the system disk in
  708. driver A: and type
  709.  
  710.                                A:PKTINFO
  711.  
  712. If a page of information appears on the screen, the packet driver
  713. is working correctly.  If a  message appears saying no packet
  714. driver was found then the packet driver was not installed 
  715. correctly.
  716.  
  717.      After the packet drivers have been verified we want to check
  718. the LAN itself.  Located on  the same disk is a program called
  719. TRANS.EXE.  This is a simple LAN communication program  that will
  720. send and receive packets from on PC to another.  Pick two machines
  721. to execute this  software on.  One one of them, write down the
  722. ethernet address as shown by PKTINFO.  Inset the  system disk in
  723. drive A: and type
  724.  
  725.                                 A:TRANS
  726.      Take the disk out and do the same for the other machine.  On
  727. the PC that will receive the  packets press SHIFT and R.  We now
  728. want to select what receive mode to use.  Press 2.  The  screen
  729. will blank and a status bar will appear at the top.  On the sender
  730. machine press SHIFT and  S.  We need to select a receive mode as we
  731. did for the receive machine.  The reason is because  the receiving
  732. machine will send an acknowledgement packet back to the sender.  So
  733. press 2.  We  are now asked if we want to use the broadcast
  734. feature.  Press N.  The program is asked for the  address of the
  735. receive machine. Enter the six bytes written down separated by
  736. spaces and press  return.  Enter a message to be sent to the
  737. receiving machine and press enter.
  738.  
  739.      The screen will blank and ask you to press a key to send a
  740. packet or shift Q to quit.  Press  any key.  If you look at the
  741. receiving machine, you message should be on the screen.  On each of 
  742. the screens, there should be a 1 in the upper right hand corner. 
  743. This indicates that one packet has  been sent and one packet has
  744. been received.  You can continue to press any key to send
  745. additional  packets.  Press SHIFT and Q when ready to quit.  
  746.  
  747.  
  748.                                  Master
  749.  
  750.      
  751.  
  752.      The master of the Parallel Lan System is the most important
  753. machine.  It can be likened to  the server of a local area network. 
  754. It must be powerful and able to handle a flood of activity by  the
  755. worker nodes and the developer.  As documented in the manual Using
  756. the Parallel Lan  System, the master should consists of
  757.  
  758.      * At least a 25-MHZ 386 IBM PC or Compatible.
  759.  
  760.      * 4 MB of RAM
  761.  
  762.      * 16-bit 32k buffer Ethernet card
  763.  
  764.      Anything above these specification will allow for better
  765. efficiency in the system.  Other  than running the system software
  766. for the master, there is nothing that can be done to the master. 
  767.  
  768. Duties
  769.  
  770.      The duties of the master are as follows
  771.  
  772.      *  Administer the MAIN tuple space of the PLS.
  773.  
  774.      *  Receive and interpret Linda instructions from multiple
  775. processors.
  776.  
  777.      *  Keep track of unanswered Linda instructions (IN,RD).
  778.  
  779.  
  780.      Those are the only responsibilities of the master.  However it
  781. is a larger responsibility  than it may appear.
  782.  
  783.  
  784. Multiple Processor Communication
  785.  
  786.      When considering the concept of multiple processor
  787. communication, image this situation.   You are sitting in the
  788. middle of a ring of sixteen people.  All of these people are trying
  789. to hold a  conversation with you AT THE SAME TIME.  The human mind
  790. simply cannot handle that much  information at the same time.  Most
  791. people can't even keep track of a single conversation.  That is 
  792. one of the jobs of the master.  
  793.  
  794.      Things begin with the ethernet card receiving a packet.  This
  795. packet is put into some  memory set aside for incoming packets. 
  796. The master system software periodically checks to see if  there are
  797. any packets in the first incoming buffer.  If there are packets, it
  798. will take as many as  there are and partial processes them and put
  799. them into a secondary buffer.  This step is crucial.   The first
  800. buffer is static.  In other words, it is of a constant size.  As
  801. much information about this  buffer as possible was defined when
  802. the master program began executing.  If it were to overflow,  some
  803. packets would be lost ( the sender would send duplicates however. 
  804. But at a lose of  execution time ).  After the packets are in the
  805. secondary buffer, the system software will  processed them fully
  806. one at a time as it has time.  Processed packets will end up in one
  807. of two  places.  Packets which represent the Linda instructions OUT
  808. and EVAL windup in the TUPLE  SPACE.  Packets representing IN, INP,
  809. RD, and RDP will end up in a request queue.  The master  system
  810. software picks from the request queue when it tries to match
  811. tuples.
  812.  
  813.      In addition to the above queues, the master also has internal
  814. data structures that it uses to  guarantee that no duplicates
  815. packets are processed.  We all know what its like to be told the
  816. same  thing over and over.  The master doesn't like it either
  817. therefore it eliminates duplicates.  Also, the  master must keep
  818. track of the order of packets from different processors.  Just like
  819. we try to say a  persons first name before their last name, the
  820. master must guarantee that a packet sent before  another packet
  821. arrives first.
  822.  
  823.      For more information on the about technical data about the
  824. system software, refer to the  document The Parallel Lan System -A
  825. Look Inside.
  826.  
  827.  
  828. Different Masters
  829.  
  830.      There is a difference in performance between different
  831. masters.  We are going to take a  look at how masters can influence
  832. the overall speed of a parallel program.  The masters used are
  833.  
  834.           *  a 4.77-MHZ 8086 IBM PC Compatible, and
  835.  
  836.           *  a 25-MHZ 80386 IBM PC Compatible.
  837.  
  838.      Each of masters was used in a comprehensive set of 40 tests
  839. using the Linda mandelbrot  program explain in a later chapter. 
  840. The test documented here was performed using from 1 to 16  workers
  841. ( 4.77 MHZ 8086 PC's using 8087 math coprocessors ) each doing 4
  842. columns per  computation.  The following table shows the difference
  843. between the masters.
  844.  
  845. Cpus    8086 Master     80386 Master    Speedup
  846. 1       642.52          577.91          11%
  847. 2       358.89          274.89          24%
  848. 4       210.80          141.65          33%
  849. 8       188.72          80.36           58%
  850. 16      ----.--         88.87           -----
  851.                                         
  852.      The chart shows the total seconds for each test using the 8086
  853. master and the 80836  master.  The far right column shows the
  854. speedup between the two systems.  There is a  considerable speedup
  855. as we approach 8 workers.  There was no test performed for 16
  856. workers  using the 8086 master.  
  857.  
  858.      Notice the increase in time between 8 and 16 workers.  This
  859. example also illustrates the  idea that adding more workers does
  860. not necessarily decrease execution time of a program.  A  faster
  861. master does indeed make a considerable impact on the speed of the
  862. execution of the  program.
  863.  
  864.      
  865. Machine
  866.  
  867.      The faster the machine, the faster the tuple space can be
  868. searched for needed tuples.  The  most work the master will perform
  869. is interpreting tuples sent to it.  The faster it can do this the 
  870. better.
  871.  
  872.  
  873. DOS
  874.  
  875.      Microsoft recently released DOS 5.0.  This DOS has many memory
  876. saving features that  the system can benefit from.  IF the master
  877. is equipped with 1 MB of memory or more, DOS can  be loaded into
  878. high memory as well as device drivers and TSR's.  All of this can
  879. save precious  lower memory.
  880.  
  881.      The master software uses lower memory ( as well as extended )
  882. to hold the tuple space.  A  system using DOS 3.3 or 4.01 will have
  883. approximately 300k of heap space available for the tuple  space. 
  884. Dos 5.0 increases this amount to approximately 360k.
  885.  
  886.  
  887. Extended Memory
  888.  
  889.      If we have 1 MB available we can take advantage of the
  890. features of DOS 5.0  Any  memory over 1 MB can be configured as
  891. extended memory by using an extended memory  manager.  The master
  892. software will take advantage of any extended memory available.
  893.  
  894.      Using extended memory for some of the tuple space is expensive
  895. as far as processing  speed is considered.  The software uses a
  896. system put into public domain to manage extended  memory.  Unlike
  897. conventional memory below 640k, extended memory cannot be accessed 
  898. directly.  A system of segments is created in extended memory. 
  899. These segments are copied into  conventional memory to be
  900. manipulated and then put back.  The segments are 32k in size.  This 
  901. means there is a 64k memory copy performed for each and every
  902. packet that must be put into  extended memory.  Now simple memory
  903. management has been put into place which will keep the  most
  904. recently used extended memory extent in conventional memory. 
  905. However, to execute  programs which has a large amount of data,
  906. extended memory is essential.  At Parallel Computer  Solutions, a
  907. 4 MB system has been used in all cases with no problem as far as
  908. space  requirements.
  909.  
  910. Network Cards
  911.  
  912.      Not all cards are created equal.  We have 8-bit, 16-bit, and
  913. 32-bit cards available for PCs.   To the best of my knowledge, 32-
  914. bit cards are available for EISA bus system only.  Therefore,  most
  915. PC's will use either the 8 or 16 bit cards.  If we have a 80286 or
  916. better machine, we will  want to use 16-bit cards.  16-bits
  917. ethernet cards have several advantages.  
  918.  
  919.      The first is the addition of 8 data lines.  More information
  920. can be transferred on 16 lines  than 8 lines.  A second reason is
  921. buffer size.  Most 8-bit ethernet cards have an 8k buffer for 
  922. incoming packets.  For most applications this is fine but the
  923. master will be receiving packets from  many different PCs at the
  924. same time.  We want to have a large buffer available if the master
  925. is  busy searching tuple space or some other system function.  16-
  926. bit ethernet cards have either 32k  or 64k buffers for incoming
  927. packets.
  928.  
  929.      You usually get what you pay for when buying a computer
  930. system.  The master is the  most important component in the
  931. Parallel Lan System and therefore it should be the best system 
  932. available.
  933.  
  934.  
  935.  
  936. Master Installation
  937.  
  938.  
  939.  
  940.      Obtain a blank diskette to copy the master software from the
  941. system diskette.  To make  the system easy to install, create a
  942. bootable diskette with the appropriate memory managers, etc  for
  943. you system.  Copy the packet driver for the ethernet card onto the
  944. new diskette.  Copy the file  MASTER.EXE to the net diskette. 
  945. Label this disk as bootable and containing the master system 
  946. software.
  947.  
  948.      Execute the master software on the appropriate machine by
  949. typing 
  950.  
  951.                                 A:MASTER
  952.  
  953.      A message will appear telling how much extended memory is
  954. available and used by the  master system.  Press return to get to
  955. the next screen.  The following should appear
  956. ( master screen - initial picture )
  957.  
  958.      This is the initial screen for the master.  The master sits in
  959. a loop waiting for a tuple to be  sent to it.  Under normal
  960. circumstances, the master does not need any attention.  The
  961. operation of  the master can be disabled by pressing any key.  As
  962. activity starts on the system, the screen will  change, this screen
  963.  
  964. ( master screen - 2 cpu picture )
  965.  
  966.    shows that 2 cpus are active on the system and the packets sent
  967. and received from those cpus.  In addition, the sizes of the heap
  968. and extended memory is given.
  969.  
  970.                                  Worker
  971.      
  972.  
  973.      The workers are an important part of the Parallel Lan System. 
  974. The workers do one thing:  perform calculations.  The least
  975. powerful machine available for a worker is:
  976.  
  977.           * 4.77 Mhz 8088 IBM PC or Compatible
  978.  
  979.           * DOS 3.3
  980.  
  981.           * 640K RAM
  982.  
  983.           * 8-bit ethernet card
  984.  
  985.      Just as in the case of the master, the performance of the
  986. Parallel Lan System can be  determined by the power of the worker
  987. machines.  Testing of the Parallel Lan System was  performed on
  988. both 4.77 Mhz 8088  workers and 20 Mhz 80386 workers.  Both systems
  989. provided  speedup simply because of the parallel execution of the
  990. test program.  But the 80386 workers  gave additional speed
  991. advantages by as much as 60/80%.  The following four charts show
  992. the  times required to perform mandelbrot using 8088 workers and
  993. 80386 workers.  The master in the  first two charts was an 8088
  994. machine.  In the second two charts, the master was an 80386 
  995. machine.
  996.  
  997. ( charts )
  998.  
  999.      In an established LAN we do not have much choice in what type
  1000. machine is used as a  worker.  The charts should show you that
  1001. processor power certainly makes a difference in both  the master
  1002. and workers.
  1003.  
  1004.  
  1005.  
  1006. Worker Installation
  1007.  
  1008.      We must now install software on each of the worker machine. 
  1009. Follow the previous  directions for setting up a master diskette
  1010. but instead of copying master.exe we need to copy a  worker
  1011. program.  
  1012.  
  1013.      Turbo Pascal is available in two different versions: 5.5 and
  1014. 6.0.  They are different in code  generation.   Therefore, we have
  1015. two different worker pieces of software called worker5.exe and 
  1016. worker6.exe.  If you are using Turbo Pascal 5.5 then copy
  1017. worker5.exe to a:worker.exe and if  you are using Turbo Pascal 6.0
  1018. then copy worker6.exe to a:worker.exe.
  1019.  
  1020.      Insert the diskette into driver A: and type
  1021.  
  1022.                                 A:worker
  1023.  
  1024.      The screen will blank and you will be asked the address of the
  1025. master.  If you did not  write the address of the master down, you
  1026. can look on the screen of the machine it is executing  on.  In the
  1027. upper left hand corner of the screen is the ethernet address of
  1028. this machine.  On each of  the worker systems, enter the six bytes
  1029. separated by spaces.  Once the system has digested the  master
  1030. address, it will attempt to establish communications with the
  1031. master.
  1032.  
  1033.      Recall that the purpose of the worker is to execute code given
  1034. to it by the developer  system.  The worker will get work from the
  1035. master by sending a tuple of the form
  1036.  
  1037.                              in ( 'work' );
  1038.  
  1039. to the master.  All packets sent over the ethernet are given a
  1040. specific number in order to keep a  sequence.  the system software
  1041. gives the number 2 to the first packet sent out by any system.  We 
  1042. can verify that a worker is communicating with the master by the
  1043. messages put on the master and  worker screens.  A worker has
  1044. communicated successfully if on the screen of the master is a 
  1045. message IN - 2 for each of the workers.
  1046.  
  1047.      Since a packet has been sent to the master, the master has to
  1048. acknowledge the packet,  therefore each of the workers should have
  1049. a message in the right most box with the number 2 next  to it.  If
  1050. this is the case, then this worker has been successful added to the
  1051. system.  If this is not  the case, then either the master's address
  1052. was not correctly entered or the address in not that of the 
  1053. master.  The worker software halts when a key is pressed.  So if no
  1054. message appears on the screen  , press a key on the worker machine
  1055. and try again by executing the worker software again.
  1056.  
  1057.  
  1058.                                Developer
  1059.  
  1060.  
  1061.      
  1062.      The developer is a machine on the system which runs and
  1063. coordinates the executing  parallel program.  It will begin a
  1064. program by submitting any number of worker processes.  The 
  1065. responsibilities of the developer are
  1066.      
  1067.      *  Submit jobs for worker processors
  1068.  
  1069.      *  Coordinate the submitted jobs
  1070.  
  1071.      *  Produce results
  1072.  
  1073.      The developer is the foreman for the Parallel Lan System.  A
  1074. programmer will code a  parallel program on the developer, compile
  1075. it, and run it without moving to different machines.   One way to
  1076. look at it is you are programming a single PC which just happens to
  1077. have any number  of subprocessors available to help speed up a
  1078. particular program.  
  1079.  
  1080.      Again it needs to be pointer out that if you are using Turbo
  1081. Pascal 5.5, the workers should  be executing worker5.exe and if you
  1082. are using Turbo Pascal 6.0, the workers should be executing 
  1083. worker6.exe.
  1084.  
  1085.      The Parallel Lan System developer software is setup to
  1086. initially recognize files with an  extension of .PLS.  Turbo Pascal
  1087. and our system files can be set up in such a way as to simplify 
  1088. use of the system.  In the root directory of you hard drive create
  1089. a directory called PLS using the  command
  1090.  
  1091.                                mkdir pls
  1092.  
  1093.      Move into that directory with
  1094.  
  1095.                                  cd pls
  1096.  
  1097.      Insert the system software diskette into drive A: and copy the
  1098. following files into our new  directory
  1099.  
  1100.                          work*.tpu
  1101.  
  1102.                          both*.tpu
  1103.  
  1104.                          *.pls
  1105.  
  1106.                          linda.exe
  1107.  
  1108.                          *.doc
  1109.  
  1110.      Now back out of this directory with 
  1111.  
  1112.                                  cd ..
  1113.  
  1114.      Using an editor change your autoexec.bat file to include the
  1115. turbo directory in the system  path.  If no PATH directive appears
  1116. in you autoexec.bat file, enter the following line
  1117.  
  1118.       path c:\tp - or whatever the turbo pascal directory name is
  1119.  
  1120.      After you have changed the file type
  1121.  
  1122.                                 autoexec
  1123.  
  1124.      This is make the change effective.  Now change into your PLS
  1125. directory and type
  1126.  
  1127.                             turbo linear.pls
  1128.  
  1129. Turbo's main screen will appear.  We need to make sure the compiler
  1130. settings are set correctly  before we do anything else.  Press ALT
  1131. and O, move to the COMPILER and press return.  Move  the bar to
  1132. FORCE FAR CALLS and change the entry to YES.  Check that the entry
  1133. BOOLEAN  EXPRESSIONS is set to SHORT-CIRCUIT.  Move to the first
  1134. menu and select the SAVE  OPTIONS entry and press return.  Save the
  1135. new options.
  1136.  
  1137.      Now on the screen will be the parallel program for solving
  1138. linear equations.  Try to  compile this program by pressing F9. 
  1139. You should get an error on the first Linda command IN.   What we
  1140. need to do is execute the conversion program LINDA.EXE.  Linda.exe
  1141. is explained in  the document, Linda Conversion Program User Guide. 
  1142. To do this in a convenient manner, press  ALT and F.  Move to the
  1143. entry EXIT TO DOS and press return.  This will exit us to DOS but 
  1144. keep Turbo Pascal in memory.  Run the conversion program by typing 
  1145.  
  1146.                               linda linear
  1147.  
  1148.      The linda program will create a file called Linear.pas that is
  1149. made up of Turbo Pascal  statements only.  Type exit and press
  1150. return.  This will return us back to Turbo Pascal.  We are  still
  1151. working on the file Linear.PLS.  Press ALT and F and move the bar
  1152. to PICK and press  return.  Pick a new file and enter linear.pas. 
  1153. This will bring up the file linear.pas.  Press F9 to  compile the
  1154. program, it will compile successfully.  If there had been an error,
  1155. we would have  wanted to press ALT and F, move the bar to PICK and
  1156. select linear.pls to make any changes, run  linda again, and select
  1157. linear.pas.  Although this may seem a hassle, it is the only way to 
  1158. incorporate a preprocessor in the Turbo environment.  Future
  1159. releases will not require this.
  1160.  
  1161.  
  1162. Compiler Directives
  1163.  
  1164.      During the development of the system, several things were
  1165. learned about how Turbo Pascal ( TP )   generates code.  TP allows
  1166. for several different types of float point variable.  Reals,
  1167. double, extended and  several other are the chooses that we have.
  1168.  
  1169.      In most applications, real variables are good enough for our
  1170. calculations.  TP will generate code  for reals automatically.  In
  1171. order to generate code to handle double or extended variables, the
  1172. compiler  directives {$N+,E+,F+} are necessary.
  1173.  
  1174.      So what the problem.  The problem comes about when there are
  1175. constants in your code.  Such as
  1176.  
  1177.                                a := 1.0;
  1178.  
  1179. The 1.0 is a constant as far as TP is concerned.  When TP generates
  1180. code for normal reals, it appears that  the constant value is
  1181. stored in the code itself.  When double or extended reals are used,
  1182. TP does not put the  constant into the code itself.  The constant
  1183. value is stored at the top of the procedure that the constant 
  1184. appears in.  The code
  1185.  
  1186.                procedure test;
  1187.                var a : extended;
  1188.                begin
  1189.                  a := 1.0;
  1190.                end;
  1191.  
  1192.      TP generates the code.
  1193.  
  1194.           0000803F       -         1.0
  1195.           55             -         push bp
  1196.           89E5           -         mov bp,sp
  1197.           B80A00         -         mov ax, 000A
  1198.           9A7C02AF5C          -         call 5CAF:027C
  1199.           83EC0A         -         sub sp,000A
  1200.           CD3C99060000   -         fld cs:dword ptr[0000]
  1201.  
  1202.  
  1203.      The mnemonic FLD loads the real constant into the 80x87 or
  1204. emulator.  The constant is located at  cs:dword ptr[0000] which
  1205. when disassembled, is the first line of this code segment.  The
  1206. main code has a  call statement CALL 0004 which calls this
  1207. procedure code thus bypassing the real value.
  1208.  
  1209.      Now what is means to us is, we should always include the
  1210. compiler directive {$N+,E+,F+} in our  program.  It is not always
  1211. needed obviously, but it is safe to include it.  If you write an
  1212. application that  uses reals, there may be an error.
  1213.  
  1214.      The system code has been tested on machines with and without
  1215. numerical coprocessors.  One test  included some workers with
  1216. coprocessors and some without.  The above compiler directive worked
  1217. for  both setups.
  1218.  
  1219.  
  1220. Units and System Code
  1221.  
  1222.      There are a considerable number of routines that are needed to
  1223. perform the operations of the  Parallel Lan System. By
  1224. incorporating these routines into a single Turbo Pascal Unit, we
  1225. are able to  successfully hide them from the developer.
  1226.  
  1227.      Turbo Pascal requires units to be included in a program by
  1228. using the command USES.  Programs  intended to execute on the PLS
  1229. should start with the code:
  1230.  
  1231.                     Program ..........
  1232.  
  1233.                     {$N+,E+,F+}
  1234.  
  1235.                     Uses work, both;
  1236.  
  1237.      There are two units for the PLS; work and both and should be
  1238. in the directory where the program  being written is.  By USEing
  1239. this unit, we have access to procedures and variables that we will
  1240. use directly  in the writing of our parallel programs.  Now in the
  1241. working directory, there are two different version of  the work and
  1242. both units.  Work5 and both5 should be used when using Turbo Pascal
  1243. version 5.x and  work6 and both6 should be used when using Turbo
  1244. Pascal 6.0.
  1245.  
  1246.  
  1247. Startup Procedure
  1248.  
  1249.      We have developed a parallel environment which operates in
  1250. coordination with Turbo Pascal.   Because of this, there are
  1251. several problems that must be dealt with directly.  To solve
  1252. several problems, a  parallel program must include, what we call,
  1253. a startup procedure.  The purpose of this procedure is two-fold. 
  1254. First is to initialize the system.  The second procedure of the
  1255. startup procedure is to border  procedure which are destined to be
  1256. sent to worker processes.
  1257.  
  1258.      Turbo Pascal creates, as far as I can tell, procedures by
  1259. first coding all real constants and placing  them into the code. 
  1260. So if a statement in the language like
  1261.  
  1262.                a := 1.0;
  1263.  
  1264. Turbo Pascal will encode the 1.0 into the code such as
  1265.  
  1266.                0000 3F55 ( or something like this )
  1267.  
  1268.      After the constants, code is generated to set up the stack for
  1269. any formal or local variables.
  1270.  
  1271.                push bp
  1272.                mov  bp,sp
  1273.                mov  ax, ----  ( the number of bytes required for
  1274. variables )              call ----
  1275.  
  1276.      There one or two calls to Turbo Pascal procedures.  It is my
  1277. guess that the stack is checked for  overflow as well as other
  1278. housekeeping activities associated with the stack.  The code to
  1279. perform the  function so the procedure are generated next.  After
  1280. this code, the stack is returned to its original state.   The last
  1281. code generated is a return instruction.  The 80x86 family of
  1282. microprocessors have several  different return opcodes. These
  1283. return opcodes are for near, far, and interrupt routines.    Our
  1284. system  requires all procedure and function calls to be generated
  1285. as far.  The reason for this is so Turbo Pascal will  always
  1286. generate a RETF instruction which  us $CB hex. By always generating
  1287. this particular instruction,  the system software can make a fairly
  1288. good guess at where a procedure ends and another begins. This, if 
  1289. we wanted to generate code for the procedures.
  1290.  
  1291.                procedure startup
  1292.  
  1293.                begin
  1294.                end;
  1295.  
  1296.                procedure tosend;
  1297.  
  1298.                begin
  1299.                end;
  1300.  
  1301.      The code generated would look something like
  1302.  
  1303.  
  1304.                ( procedure startup )
  1305.  
  1306.                $55  push bp
  1307.                     mov  sp,bp
  1308.                     mov  ax,----
  1309.                     call
  1310.  
  1311.                     .
  1312.                     .
  1313.                     .
  1314.  
  1315.                $CB  retf
  1316.  
  1317.                ( procedure tosend )
  1318.                $55  push bp
  1319.                     mov  sp,bp
  1320.                     mov  ax,----
  1321.                     call
  1322.  
  1323.                     .
  1324.                     .
  1325.                     .
  1326.  
  1327.                $CB  retf
  1328.  
  1329.      If our code was going to send the procedure tosend to a worker
  1330. node, we would grab the starting  location of the procedure, say
  1331. 0030 hex, by using the @ operator of Turbo Pascal.  The system code 
  1332. backtracks until it finds a $CB value.  What we are doing is
  1333. looking for any real constants.  The memory  from the start of a
  1334. procedure back to the next procedure's end $CB is copied to the end
  1335. of the code we are  sending to the workers.
  1336.  
  1337.      Now why the startup procedure.  If we did not have a procedure
  1338. coded before the procedure we are  sending to the nodes, the system
  1339. could search for a long time before another $CB is encountered.  By 
  1340. incorporating the startup procedure, we are guarantee to find a
  1341. $CB.  The turbo debugger invaluable when  trying to determine
  1342. exactly what Turbo Pascal does during code generation.
  1343.  
  1344.      The startup procedure should be included in the developer code
  1345. right after the compiler directives.
  1346.  
  1347.                Program ...............
  1348.  
  1349.                {$N+,E+,F+}
  1350.  
  1351.                Procedure startup;
  1352.  
  1353.                begin
  1354.  
  1355.                end;
  1356.  
  1357.      Now that we have the basics of the startup procedure, we need
  1358. to put some code into it.  The first  two lines of the procedure
  1359. are
  1360.  
  1361.  
  1362.                exitsave := exitproc;
  1363.                exitproc := @myexit;
  1364.  
  1365. These lines of code link our exit procedure into the system exit
  1366. procedure which is part of any Turbo  Pascal program.  In the event
  1367. of a run-time error, our exit routine will do some internal memory 
  1368. deallocation and other system functions that allow the system to
  1369. fail gracefully.
  1370.      The next size lines of code identify which machine is the
  1371. master.  Ethernet addresses are codes as  six bytes which as 00 00
  1372. C0 05 86 24 hex.  Find out the address of the ethernet card the
  1373. master system  software will execute on using the pktinfo program
  1374. included with the system.  The lines of code necessary  to identify
  1375. the master to the developer program looks like
  1376.  
  1377.                master[x] := $yy;
  1378.  
  1379. There should be six lines identical to the above with x ranging
  1380. from 1 to 6.  The $ operator identifies the  following two
  1381. characters are hexidecimal.
  1382.  
  1383.      The last line of code in the startup procedure is
  1384.  
  1385.                init_system;
  1386.  
  1387. The system initialization code has been put into this single call
  1388. in order to keep the startup procedure as  simple as possible.
  1389.  
  1390.  
  1391. Procedure Declarations
  1392.  
  1393.      The power of the Parallel Lan System lies in the ability to
  1394. send procedures to worker nodes.  The  system is not limited to
  1395. just sending of a single procedure.  Any number of procedures can
  1396. be sent to  workers.  There are several rules that have to be
  1397. followed when designing procedure which will be sent to  workers.
  1398.  
  1399.  
  1400. Global Variables
  1401.  
  1402.      When Turbo Pascal compiles a program, space is set aside in a
  1403. separate data segment in the PC's  memory for variables.  The
  1404. memory location of a specific variable is recorded in the compiled
  1405. code.  If a  global variable is reference in a procedure sent to a
  1406. worker, the value obtained when this variable is used  will not be
  1407. the value that we want.  The contents of the memory location
  1408. referenced will be undetermined  because the worker was not aware
  1409. that of that particular global variable.
  1410.  
  1411.      Worse yet is the assignment of a global variable.  The value
  1412. assigned to the variable will be placed  in the workers memory
  1413. somewhere.  It is possible that the assignment will cause the
  1414. worker to fail.
  1415.  
  1416.      Global variables should be passed by the developer to worker
  1417. machine through the Linda  instructions and the tuple space.
  1418.  
  1419.  
  1420. Readln/Writeln
  1421.  
  1422.      Procedures sent to workers cannot have readln or writeln
  1423. statements in them.  The reason for this is  Turbo Pascal treats
  1424. the screen and keyboard as files.  If used, a FILE NOT OPENED error
  1425. will appear and  the worker will fail.
  1426.  
  1427.  
  1428. Formal Parameters
  1429.      
  1430.      There can not be formal parameters in the procedures sent to
  1431. workers.  Because we are using a  version of the Linda coordination
  1432. language, there is no need for formal parameters.  The function of 
  1433. formal parameters are performed by Linda instructions.
  1434.  
  1435.  
  1436.  
  1437. Nesting Procedures
  1438.  
  1439.      Turbo Pascal does not follow the source code exactly when
  1440. generating code.  One such case is  nesting procedures. Logic would
  1441. dictate that the code generated would model that of the source,
  1442. where by  the procedure code generated by the compiler would
  1443. include procedure nesting.  Turbo Pascal does not do  this, nor
  1444. should it.  Nested procedures are coded as single procedures and a
  1445. call in made to them as needed.   This however causes us some
  1446. problems.  When our system generates tuples to send to workers, it
  1447. is  performed at runtime, therefore we do not have access to the
  1448. symbol table.  We cannot determine which  procedure to send and
  1449. which not to.  The end result is we are unable to handle nested
  1450. procedures with this  release of the system.
  1451.  
  1452.  
  1453. Multiple Procedures
  1454.  
  1455.      There are programs which are prone to decomposition requiring
  1456. multiple procedures.  The system  is setup such that procedure sent
  1457. to workers can coexist with normal procedures.  The developer can
  1458. use  normal procedures during the execution of a program.  When a
  1459. program has more than just a single  procedure to be sent to the
  1460. worker nodes, order is not important.  The system will locate the
  1461. appropriate  procedure when asked for.  
  1462.  
  1463.      Say we have a program which requires two different procedure
  1464. to be sent to workers.  Can the  developer program or programmer
  1465. determine which worker will get which procedure?  No, we can not 
  1466. determine in what order the workers will get the procedures.  If it
  1467. is important, a system of semaphores could be used.
  1468.  
  1469.  
  1470. CAUTION!
  1471.  
  1472.      There is one important note that must be made about the code
  1473. that can appear in a worker procedure.  Turbo Pascal performs smart
  1474. linking when ever a program is compiled.  In other words, if you
  1475. use the sqrt library function, it is extracted from the system unit
  1476. and placed in your code.  The entire system unit is not compiled
  1477. with your code.  Therefore, STATEMENTS FROM THE SYSTEM UNIT CANNOT
  1478. BE USED IN YOUR WORKER PROCEDURES!  The reason for this is the
  1479. worker software cannot effectively be compiled with all of the
  1480. functions included in the system unit.  Once again, this is a
  1481. limitation brought about from building this system on top of the
  1482. conventions of a pre-existing compiler.
  1483.  
  1484.  
  1485. Developer Program Design
  1486.  
  1487.      Parallel programming is no easy nor is it straightforward.  In
  1488. this section, I would like to give a  few points on understanding
  1489. the task at hand.  This is by no means a tutorial on parallel
  1490. programming.
  1491.  
  1492.      All parallel system are different.  Then again so are all
  1493. programming languages.  Bit as computer  scientists, we are
  1494. required to be able to learn new programming languages easily. 
  1495. Learning to program the  Parallel Lan System can be an
  1496. uncomplicated task if the problem we want to solve is correctly 
  1497. decomposed.
  1498.  
  1499.      The Parallel Lan System is designed as a distributed structure
  1500. machine.  The information or data  structures we develop for our
  1501. problem are kept on a single machine, the master.  In order to
  1502. access this  information, a request is sent to the master by way of
  1503. a tuple.  There can be potentially a large amount of  information 
  1504.  passed among the different systems.  The designer of a parallel
  1505. program on the PLS must  keep this i mind.  Take for instance on
  1506. the of the example programs described in the main documentation.  
  1507. Mandelbrot is typically designed as a sequential program which
  1508. executes on a single pixel at a time.   When writing Mandelbrot for
  1509. a parallel machine, several options are available.  Do we want each 
  1510. processor to execute the algorithm on a single pixel before
  1511. returning result, a column, a row , or multiple  of each.  The main
  1512. documentation describe the result .  But suffice it to say,
  1513. executing on a single pixel at  a time will achieve parallelism
  1514. because some number of processors will be calculating a pixel value
  1515. at any  given moment.  Bit is not optimal.  There is too much
  1516. communication between processors.  We can  achieve better results
  1517. with a particular number of processors by increasing to a column or
  1518. more.
  1519.  
  1520.      This brings up another point, there are times when adding
  1521. processors to the system will result in a  degradation of the
  1522. system as a whole. 
  1523.  
  1524.  
  1525. Tuning
  1526.      There will almost always be some parameters in a parallel
  1527. program that will judge the ultimate  speed of the program on the
  1528. system.  It must be kept in mind that the key to parallel
  1529. programming is to get  an initial program up and running.  After
  1530. the program is running, test it and compare to other platforms.
  1531.  
  1532.                A sequence program executing on a single processor
  1533.  
  1534.                A one - worker Parallel Lan System
  1535.  
  1536.                A two - worker Parallel Lan System
  1537.  
  1538.                A four - worker Parallel Lan System
  1539.  
  1540.                An eight - worker Parallel Lan System
  1541.  
  1542.      Graph the results ( using execution time ) on a chart.  This
  1543. will help illustrate the speed up  achieved from going to parallel
  1544. execution.  Do not be surprised if several of the tests are slower
  1545. than a  sequential program.  At some point, adding more processor
  1546. should achieve results faster than the  sequential program.  A rule
  1547. of thumb can be used in general.  If after executing the algorithm
  1548. on a four  processor system the results are not achieved faster
  1549. than a sequential program, something is wrong with  the design of
  1550. the program.  But before submitting to a redesign, check the
  1551. establish or try to establish  tunable parameters.  There are
  1552. always some variables or aspects of the algorithm used in the
  1553. program  which can be tuned to achieve faster results.
  1554.  
  1555.      The pixels was a tunable parameter in the Mandelbrot program. 
  1556. In a fiance program it could be the  number of variables used in a
  1557. regression or the number of data points examined.  In the linear
  1558. algebra  program shown in the main documentation, its the number of
  1559. columns calculated by each processor.
  1560.  
  1561.  
  1562. Debugging
  1563.  
  1564.      A parallel program can sometimes be more of a challenge than
  1565. writing the parallel program itself.   As of this release there are
  1566. no debugging facilities, but the source code is provided so you can
  1567. add any  support you feel necessary. My only remark on this subject
  1568. is to run your program on a one worker system  and count out pieces
  1569. of the code until you have identified where the problem occurs. 
  1570. Then run on a two  worker system and do the same thing.  Just
  1571. remember the you have many different tasks executing at the  same
  1572. time.  A key to debugging a parallel program is to understand the
  1573. relationship between these  different tasks.
  1574.  
  1575.  
  1576. Main 
  1577.  
  1578.      In the main section of the developer program, the first
  1579. statement should be a call to start_up.   Your code for the actual
  1580. program goes next.  After the code, the statement close_system ends
  1581. the main  section.
  1582.  
  1583.                     begin
  1584.  
  1585.                       start_up;
  1586.  
  1587.                     { user code }
  1588.  
  1589.                       close_system;
  1590.  
  1591.                     end.
  1592. Skeleton Code
  1593.  
  1594.      The following is a skeleton of the necessary code for a
  1595. developer program.  It should reproduced  and placed in a .PLS file
  1596. for easy access.  The easiest way for keeping the code separate is
  1597. to name this  code skel.pls and perform a copy when developing a
  1598. new application.
  1599.  
  1600. program ------;
  1601.  
  1602. {$N+,E+,F+}
  1603.  
  1604. uses both, work;  { remember: append 5 or 6 to the end of work and
  1605. both depending on the version of tp }
  1606.  
  1607. procedure start_up;
  1608.  
  1609. begin
  1610.  
  1611.   exitsave := exitproc;
  1612.   exitproc := @myexit;
  1613.  
  1614.   master[1] := $--;
  1615.   master[2] := $--;
  1616.   master[3] := $--;
  1617.   master[4] := $--;
  1618.   master[5] := $--;
  1619.   master[6] := $--;
  1620.  
  1621.   init_system;
  1622.  
  1623. end;
  1624.  
  1625. { user procedures }
  1626.  
  1627. begin
  1628.  
  1629.   start_up;
  1630. { user code }
  1631.  
  1632.   close_system;
  1633.  
  1634. end.
  1635.  
  1636.  
  1637. What the Developer Doesn't Show
  1638.  
  1639.   The developer is an independent program.  You will not see the
  1640. same displays as the master and  worker have.  Therefore, there
  1641. should be some activity on the developers screen.  The  programmer
  1642. will have to provide this activity.  The example programs are all
  1643. graphical in nature  therefore it is quite easy to see that
  1644. everything is going normally.  The programmer will want  some kind
  1645. of indication from the developer as to the state of the system as
  1646. far as the developer is  concerned.
  1647.  
  1648.  
  1649. RELAX!
  1650.  
  1651.      The most important thing to remember when developing parallel
  1652. programs is to relax.   Parallel programming takes time and
  1653. patience.  Parallel programs have to be planned, in my  opinion,
  1654. much more than sequential programs.  The results for this is that
  1655. in a sequential  program, one instruction is going to follow
  1656. another.  Even in the case of decisions and loops.   There is no
  1657. question about it.  It can be traced and reproduced many times.  (
  1658. Unless there is a  subtle bug in the program that occurs only every
  1659. three thousand iterations ).  In a parallel  program, there is
  1660. absolutely no guarantee as to the order that instructions will be
  1661. executed by the  different machine.  Even if the workers are
  1662. executing the same piece of code.  
  1663.  
  1664.      I strongly recommend coding the programs presented later and
  1665. running them.  Get  comfortable with the system and then
  1666. experiment.  You can always reset the machines and start  the
  1667. system again if something really messes up.  
  1668.  
  1669.                                PCS-Linda
  1670.  
  1671.  
  1672.  
  1673.      In the above section on LINDA, we touched on the different
  1674. instructions and either use in  coordinating parallel programs. 
  1675. Now we want to look at PCS-Linda.  PCS-Linda is the dialetic  of
  1676. Linda that the Parallel Lan System is programmed with; along with
  1677. Turbo Pascal.  In order to  get Linda is execute using a pre-
  1678. existing compiler, several requirements had to be made as far as 
  1679. using Linda was concerned.  This section will discuss those
  1680. requirements.
  1681.  
  1682.  
  1683. Linda Conversion Program
  1684.  
  1685.      Turbo Pascal will not recognize PCS-Linda.  Try it once.  You
  1686. will get an error message  on any of the six instructions.  The
  1687. Linda Conversion Program ( LCP ) is a preprocessor for the  PLS and
  1688. PCS-Linda.  After you have coded a parallel program using Turbo
  1689. Pascal and PCSL,  you must give the program a name ending with the
  1690. extension '.PLS'.  Once this file is created,  you can run the LCP
  1691. to convert your program.  LCP will perform some magic and produce
  1692. a file  with the same name ending with '.PAS'.  This file can now
  1693. be successfully compiled with Turbo  Pascal.
  1694.  
  1695.      The LCP will produce code that Turbo Pascal can recognize for
  1696. each of the linda  commands.  If there is an error in the Turbo
  1697. Pascal code, verify that all variable have been  declared and
  1698. things like this.  Always remember to make changes to the '.PLS'
  1699. file and not the  '.PAS' file.  For more information about LCP,
  1700. refer to the document Linda Conversion  Program.
  1701.  
  1702.   
  1703. Tuple Elements
  1704.  
  1705.      Tuples in PCS-Linda can consist of zero to six elements.  The
  1706. elements can be one of four  different types
  1707.  
  1708.      *  Actuals
  1709.  
  1710.      *  Formals
  1711.  
  1712.      *  Data
  1713.  
  1714.      *  Null
  1715.  
  1716.      Actuals and formal elements will be discussed next.  The last
  1717. two types, the programmer  and user have no control over.  When an
  1718. EVAL instruction is executed, a procedure is sent to the  master or
  1719. worker.  This procedure is considered to be a data element.  In
  1720. reality it is an actual but  there are special needs that must be
  1721. met when searching and transferring procedure to and from  the
  1722. different machines.  The data type allows for cleaner code.       
  1723. The null type is used in every tuple where there is less than six
  1724. elements.  Elements not  used in a tuple are given the type null. 
  1725. The null type uses no memory therefore it is a convenient  form of
  1726. termination for these empty elements.
  1727.  
  1728.  
  1729. Actuals - Integer/Real
  1730.  
  1731.      Using a pre-existing compiler caused several different things
  1732. to happen in the  development of the Parallel Lan System and its
  1733. associated Linda language.  This can be seen  when using actuals
  1734. and formals in the tuples.  
  1735.  
  1736.  
  1737. Integers
  1738.  
  1739.      Turbo Pascal has several different types of integers; integer,
  1740. long, word, byte.  Each of  these can be used in a tuple but there
  1741. is a rule to their use.  If an integer is to be sent in a tuple, it 
  1742. can be represented in two ways.  The first is to put the integer
  1743. into the tuple
  1744.  
  1745.                            ('info', 1, 5, 8)
  1746.  
  1747.      The 1, 5 and 8 will be interpreted as integer and stored
  1748. accordingly.  The integer used in  the two-complement two-byte
  1749. integer.  Therefore the tuple
  1750.  
  1751.                            ('info', 1234567)
  1752.  
  1753. would case a compile error when the final code was compiled.  This
  1754. number is too large for an  integer stored in two bytes.  The same
  1755. is true if an single byte was to be sent.  It would be stored  in
  1756. two-bytes instead of one.  In order to sent the above number, we
  1757. could use the tuple
  1758.  
  1759.           
  1760.           bigint : long;
  1761.           
  1762.           bigint := 1234567;
  1763.  
  1764.           ( 'info', &bigint );
  1765.  
  1766.      This tuple would effectively send the large number to the
  1767. master.  We would do the same  for a byte
  1768.  
  1769.           smallint : byte;
  1770.  
  1771.           smallint := $32;
  1772.  
  1773.           ( 'info', &smallint );
  1774.  
  1775.      Remember that the tuple sent to match either of the above
  1776. tuples would also have to have  the receiving integer declared as
  1777. either a long or a byte.
  1778.  
  1779.  
  1780. REALS
  1781.  
  1782.      The same situation as above occurs with reals as well.  When
  1783. a real is put into a tuple
  1784.  
  1785.                        ( 'info', 1.234, 1.4E+3 )
  1786.  
  1787.      The real is evaluated as a 6-byte real number.  This is an
  1788. acceptable real number for most  applications but in the case of
  1789. more complex mathematics, a large real may be necessary.  Turbo 
  1790. Pascal support reals as either real, single, double, extended, and
  1791. comp.  Each of these tpus can be  used just as we did for integers. 
  1792. To send the real number 1.234e+1023 we would use the tuple
  1793.  
  1794.           bigreal : extended;
  1795.  
  1796.           bigreal := 1.234e+1023;
  1797.  
  1798.           ( 'info', &bigreal );
  1799.  
  1800.      Again, the variable to receive this real number would have to
  1801. declared as an extended as  well.
  1802.  
  1803.  
  1804. Formals 
  1805.  
  1806.      Formals must match the types they are to receive.  Because we
  1807. are programming both the  code the worker will receive and the code
  1808. the developer will execute, we can easily match the  types. 
  1809. However, it may happen that in a case where we were using reals and
  1810. the accuracy was  not enough so we change to extended reals, we
  1811. missed a declaration.  The system will not match  the tuple because
  1812. a standard real is 6 bytes and an extended is 10 bytes in length. 
  1813.  
  1814.  
  1815.  
  1816. INP & RDP
  1817.  
  1818.      The pre-existing compiler strikes again.  The INP and RDP
  1819. instruction treated as function  normally.  They will returned
  1820. either true or false if a tuple was matched by the master. 
  1821. However,  we were unable to get the functionality of these two
  1822. instructions exactly.  In PCS-Linda the RDp  and INP instructions
  1823. must be assigned to a boolean variable such as
  1824.  
  1825.                      ok := RDP ( 'info', bigreal );
  1826.  
  1827.      If a tuple was matched, bigreal will contain the real value
  1828. sent with the tuple and ok will  be set to true.  If a null tuple
  1829. was sent by the master, ok will be set to false, and bigreal will
  1830. not be  changed.  If we were to use the RDP ( INP can be
  1831. substituted wherever RDP is used ) to control a  loop we would do
  1832. the following
  1833.  
  1834.           ok := rdp ( 'info', bigreal );
  1835.           counter := 1;
  1836.           while not ok do
  1837.             begin
  1838.               inc ( counter );
  1839.               ok := rdp ( 'info', bigreal );
  1840.             end;
  1841.  
  1842.  
  1843.      This loop would count the number of times the RDP instruction
  1844. was used before a  successful tuple match was found.  In Original
  1845. Linda from Scientific Computing Associates, Inc.  this loop would
  1846. appear as
  1847.  
  1848.           
  1849.           counter := 1;
  1850.           while not rdp ( 'info', bigreal ) do;
  1851.             inc ( counter );
  1852.  
  1853.  
  1854.      This is not a big change but it is one that should be kept in
  1855. mind when using the RDP and  INP instructions.
  1856.  
  1857.  
  1858. EVAL
  1859.  
  1860.      The EVAL instructions is used to send a procedure to be
  1861. executed by a worker.  PCS-Linda only allows one element in the
  1862. tuple used for the EVAL instruction
  1863.  
  1864.      *  The first element must be &procedure name
  1865.  
  1866.      The name of the tuple must be 'work'.  The worker system
  1867. software has been precompiled  to look for a tuple of this name
  1868. with the above elements.  Because duplicate elements are allowed 
  1869. in tuple space, the name 'work' will not cause a problem when
  1870. sending more than a single  procedure to be executed by workers. 
  1871. Thus the tuples
  1872.  
  1873.                        eval ( 'work', &compute );
  1874.  
  1875.                        eval ( 'work', &result );
  1876.  
  1877. will not conflict with each other.
  1878.  
  1879.  
  1880. Tuple Size
  1881.  
  1882.      The tuple size of the present Parallel Lan System is 16000
  1883. bytes.  This will allow a large  amount of data to be sent between
  1884. machine per instruction.  If this is not acceptable for your 
  1885. situation, you receive garbage when trying to execute your parallel
  1886. program, ( the workers will  probably get confused as your code
  1887. executes ), call us and we can increase your systems tuple  size. 
  1888.  
  1889.  
  1890.  
  1891. What Does OUT (); Produce
  1892.  
  1893.   Lastly, we would like to show what the instruction
  1894.  
  1895.  
  1896.           var
  1897.  
  1898.             start_col : integer;
  1899.             results   : array[1..200] of integer;           
  1900.  
  1901.           out ( 'col', &start_col, &results );
  1902.  
  1903.  
  1904. produces when put through the Linda Conversion Program.
  1905.  
  1906.  
  1907. begin
  1908. make_tuple ( 3, 'c', 'o', 'l', ' ',' ',' ',' ',' ',' ',' ',' ','
  1909. ',' ',' ',' ',' ', @start_col, sizeof (start_col), yes,
  1910. @results, sizeof (results), yes,
  1911. nil,0,null,
  1912. nil,0,null,
  1913. nil,0,null,
  1914. nil,0,null 
  1915. );
  1916. send_tuple ( out );
  1917. end;
  1918.  
  1919.      All of the above is required for a single PCS-Linda
  1920. instruction.  It is beyond the scope of  this guide to detail what
  1921. is being done here.  For more information about the technical
  1922. nature of  the Parallel Lan System consult the paper - Parallel Lan
  1923. System - A Course In Overcoming.
  1924.  
  1925.  
  1926.  
  1927.                           An Example
  1928.  
  1929.  
  1930.  
  1931.      Let's start using the things we have learned by formulating an
  1932. example exercise.  We want  to have multiple processors find the
  1933. sum of all the integers between 1 and 20.  We want to write  the
  1934. program in PCS-Linda and Turbo Pascal.  Because of the nature of
  1935. the PLS, if your system  only has a single worker, the code will
  1936. still execute correctly.
  1937.  
  1938.      We want our developer to put the numbers 1 through 20 into
  1939. tuple space and wait for a  sum to be computed.  the first thing we
  1940. should consider is what our workers are going to do.
  1941.  
  1942.      Our workers are suppose to take a number and add it to a sum. 
  1943. The workers are going to  get this number and the sum from tuple
  1944. space.  So let's get these two things
  1945.  
  1946.                     in ( 'num', a );
  1947.                     in ( 'sum', sum );
  1948.  
  1949.      Both a and sum will be declared as integers for this problem. 
  1950. Once the worker has these  two things, it will add the number in a
  1951. to the running sum.
  1952.  
  1953.                     sum := sum + a;
  1954.  
  1955.      After which, the worker has to put the new sum back in tuple
  1956. space.
  1957.  
  1958.                out ( 'sum', &sum );
  1959.  
  1960.      The worker is finished.  Several questions should come to
  1961. mind.  First of all, why did we  IN both a and sum, why not use RD
  1962. instead.
  1963.  
  1964.      The first thing that we want to happen is a worker to get the
  1965. sum, which should be zero  since we are starting the addition
  1966. sequence.  The worker should then get one of the numbers to  add to
  1967. the current sum.  The first worker will request the current 'sum'
  1968. tuple and a 'num' tuple.   The worker will add the number to the
  1969. sum and get a value of 1 for sum.  This new sum is placed  back in
  1970. tuple space for the next worker.  If we did not remove the 'sum'
  1971. and 'num' tuple, we  would have a tuple space that was filled with
  1972. multiple 'sum' tuples and duplicate 'num' tuples.   When the next
  1973. worker requests a 'sum' and a 'num' tuple, it may get the 'sum'
  1974. tuple that has a  value of 0 and not the one with the value of 1.
  1975.  
  1976.      The duty of the developer program was to put the work
  1977. procedure and necessary values in  tuple space.  The code will look
  1978. like
  1979.                     out ( 'sum', 0 );
  1980.                     for i := 1 to 20 do
  1981.                       begin
  1982.                         eval ( 'work', &worker );
  1983.                         out ( 'num', &i );
  1984.                       end;
  1985.  
  1986.      The developer will end by INing the ending sum and printing
  1987. the result.
  1988.  
  1989.                     in ( 'sum', &sum );
  1990.  
  1991. The program looks like this:
  1992.  
  1993.           program add;
  1994.           {$N+,E+,F+}
  1995.           uses work, both;
  1996.  
  1997.           var  i, sum : integer;
  1998.  
  1999.           procedure startup;
  2000.           begin
  2001.             exitsave := exitproc;
  2002.             exitproc := @myexit;
  2003.           
  2004.             master[1] := $--;
  2005.             master[2] := $--;
  2006.             master[3] := $--;
  2007.             master[4] := $--;
  2008.             master[5] := $--;
  2009.             master[6] := $--;
  2010.  
  2011.             init_system;
  2012.           end;
  2013.  
  2014.           procedure worker;
  2015.           var a, sum : integer;
  2016.           begin
  2017.             in ( 'num' , a );
  2018.             in ( 'sum', sum );
  2019.  
  2020.             sum := sum + num;
  2021.  
  2022.             out ( 'sum', &sum );
  2023.           end;
  2024.  
  2025.           begin
  2026.             startup;
  2027.  
  2028.             out ( 'sum', 0 );
  2029.  
  2030.             for i := 1 to 20 do
  2031.               begin
  2032.                 eval ( 'work', &worker );
  2033.                 out ( 'num', &i );
  2034.               end;
  2035.  
  2036.             in ( 'sum', sum );
  2037.             writeln ( sum );
  2038.  
  2039.             close_system;
  2040.           end;
  2041.  
  2042.  
  2043. Analysis
  2044.  
  2045.      Now look at this code carefully.  As soon as the worker
  2046. receive their procedures to  execute, they try to IN two tuples
  2047. named 'num' and 'sum'.  But what does the developer do, it 
  2048. immediately tries to IN the 'sum' tuple.  Now we cannot predict who
  2049. will get the 'sum' tuple first  but the developer is in line to get
  2050. it.  We want the developer to IN the 'sum' tuple after all tuples 
  2051. have added the values to sum not while they are currently adding
  2052. the values.
  2053.  
  2054.      We must put something into the code which will delay the
  2055. developer from getting the  'sum' tuple until after all workers
  2056. have added all values to sum.  We could put a delay, time wise, 
  2057. into the developer code.  Delays are dangerous though.  Too many
  2058. parameters go into the  circumstances surrounding delays.  We need
  2059. a tuple that can be increment when a value is added  to sum; like
  2060. a loop control variable.  We can do this fairly easily in PCS-
  2061. Linda.  Let's define a  tuple called 'count'
  2062.  
  2063.                     ( 'count', count );
  2064.  
  2065.      Before any values are added to sum, count should be set to
  2066. zero and placed into the tuple  space.
  2067.  
  2068.                     out ( 'count', 0 );
  2069.  
  2070.      The worker code must include instructions to read the 'count'
  2071. tuple and increment it when  a value is added to sum.
  2072.  
  2073.                     in ('count', count );
  2074.                     inc ( count );
  2075.                     out ( 'count, &count );
  2076.  
  2077.      The most important part is up to the developer.  We do not
  2078. want to read the final 'sum'  tuple until after all values have
  2079. been added to sum.  We have two instructions that can be used; 
  2080. either IN or RD.  If we use RD it will leave the 'count' tuple in
  2081. the tuple space.  So let's use IN.   But what do we want to IN.  We
  2082. want to read the final count of 20.
  2083.                     in ( 'count', 20 );
  2084.  
  2085.      This IN instructions will send a tuple to be matched to the
  2086. master.  Nothing will happen in  the developer until a match is
  2087. made with the tuple 'count' having a value of 20.  
  2088.  
  2089.  
  2090. Final Code
  2091.  
  2092.           program add;
  2093.           {$N+,E+,F+}
  2094.           uses work, both;
  2095.  
  2096.           var  i, sum, count : integer;
  2097.  
  2098.           procedure startup;
  2099.           begin
  2100.             exitsave := exitproc;
  2101.             exitproc := @myexit;
  2102.           
  2103.             master[1] := $--;
  2104.             master[2] := $--;
  2105.             master[3] := $--;
  2106.             master[4] := $--;
  2107.             master[5] := $--;
  2108.             master[6] := $--;
  2109.  
  2110.             init_system;
  2111.           end;
  2112.  
  2113.           procedure worker;
  2114.           var a, sum : integer;
  2115.           begin
  2116.             in ( 'num' , a );
  2117.             in ( 'sum', sum );
  2118.  
  2119.             sum := sum + num;
  2120.  
  2121.             out ( 'sum', &sum );
  2122.  
  2123.             in ( 'count', count );
  2124.             inc ( count );
  2125.             out ( 'count' , &count );
  2126.  
  2127.           end;
  2128.  
  2129.           begin
  2130.             startup;
  2131.  
  2132.             out ( 'sum', 0 );
  2133.             out ( 'count', 0 );
  2134.  
  2135.             for i := 1 to 20 do
  2136.               begin
  2137.                 eval ( 'work', &worker );
  2138.                 out ( 'num', &i );
  2139.               end;
  2140.  
  2141.             in ( 'count', 20 );
  2142.  
  2143.             in ( 'sum', sum );
  2144.             writeln ( sum );
  2145.  
  2146.             close_system;
  2147.           end;
  2148.  
  2149.  
  2150.                
  2151.  
  2152.                                Mandelbrot
  2153.  
  2154.  
  2155.  
  2156.      Mathematicians are able to generate wonderful things with
  2157. numbers.  One particular thing created from numbers are pictures. 
  2158. The mandelbrot complex number set is a  set of numbers that when
  2159. put through a particular set of equations generates a picture. 
  2160. This  manual is not the place for a detailed description of the
  2161. mandelbrot calculations.  Books on fractals will typically have a
  2162. detailed look at mandelbrot  numbers.  We will describe as much as
  2163. needed for the calculations and the parallel program we  will
  2164. write.  
  2165.  
  2166.  
  2167. Graphics Screen
  2168.  
  2169.      In order to plot a picture on a graphics screen, we have to
  2170. create a relationship between  each of the pixels on the screen and
  2171. a particular complex number.  For the mandelbrot program  we
  2172. present, we are going to concentrate on a 320 x 200 portion of the
  2173. VGA graphics screen  available on IBM PCs or compatible.
  2174.  
  2175.      Since we are going to be using complex number is the
  2176. calculations, we need to define  what a complex number is.  A
  2177. complex number has both a real and an imaginary part for each 
  2178. number.  There will always be two number for every complex number. 
  2179. Turbo Pascal does not  have a complex number type.  Using the TYPE
  2180. feature of Pascal, we can create a complex number type 
  2181.  
  2182.                               type
  2183.                                    complex = record
  2184.                                      realp,
  2185.                                      imag   : extended;
  2186.                                    end;
  2187.  
  2188. The nature of the calculations suggests that we use extended real
  2189. units in order to achieve the best  possible accuracy.
  2190.  
  2191. For the mandelbrot calculations, a corner value is selected which
  2192. acts as a reference point for the  calculations
  2193.  
  2194.                            bcorner : complex;
  2195.  
  2196. This corner represented the upper left hand corner.  For the
  2197. standard mandelbrot picture, bcorner  is given the value
  2198.  
  2199.                     bcorner.realp := -2.0;
  2200.                     bcorner.imag  := -1.25;
  2201.  
  2202. In addition to the corner, we must know the lengths of the sides of
  2203. the picture both width and  height.  The value typically used for
  2204. both the width and height is 2.50.  Notice that all of these 
  2205. values can be changed to get different pictures of the mandelbrot
  2206. set.
  2207.  
  2208. The last values needed for the calculations are called gap values. 
  2209. The calculations are such that  the precision of the numbers can be
  2210. changed for different screen resolutions.  The calculations use 
  2211. two different gap values, one for the width of the graphics screen
  2212. and one for the height.  
  2213.  
  2214.                     gap1 : extended; {width}
  2215.                     gap2 : extended; {height}
  2216.  
  2217. Because all of the calculations will use the same gap values, they
  2218. can be predefined.  The gap  values are calculated by taking the
  2219. length of each side ( 2.50 ) and divide it by the number of  pixels
  2220. in each dimension.  Therefore we have the values
  2221.  
  2222.                     gap1 := 2.50 / 320;
  2223.                     gap2 := 2.50 / 200;
  2224.  
  2225. What these gaps say is there is 2.50/320 space between pixels on
  2226. the graphics screen being used  to display the mandelbrot number
  2227. set.  When higher resolution screens are used, the gap gets 
  2228. smaller and smaller thus enhancing the resolution of the picture.
  2229.  
  2230.  
  2231. Sequential Program
  2232.  
  2233.      We have the basic values for the mandelbrot picture we wish to
  2234. procedure.  The only thing left is to do the actual calculations.
  2235. The calculation that must be done  for each pixel is
  2236.  
  2237.                     z := z2 + bcorner;
  2238.  
  2239.      When the size of z grows to be greater than 4.0, we can stop
  2240. the calculations.  Mandelbrot  numbers are characterized by not
  2241. approaching 4.0.  Therefore, these number could be put through  the
  2242. above equation many times.  This suggests that we need some sort of
  2243. variable to control the  total number of times we do the
  2244. calculation.  A good control value would be 50.  If a value is put 
  2245. through the calculation 50 times and the size is less than 4.0, the
  2246. number belongs to the  mandelbrot set.  Values in the mandelbrot
  2247. set
  2248. are colored black in our picture.  Values that reach 4.0 before 50
  2249. are colored different colors.  
  2250.  
  2251.      The actual calculation procedure will appear this way
  2252.  
  2253. function calculate ( col, row, bcorner, ncomplex ) : integer;
  2254.  
  2255. begin
  2256.   size := 0.0;
  2257.   result := 0;
  2258.   original.realp := ncomplex.realp;
  2259.   original.imag  := original.imag;
  2260.  
  2261.   while ( results < 50 ) and ( size < 4.0 ) do
  2262.     begin
  2263.       original.realp := sqr(original.realp) - sqr ( original.imag
  2264.                          ) + ncomplex.realp      
  2265.       original.imag  := 2*original.realp*original.imag +
  2266.                          ncomplex.imag;       
  2267.       size := sqr ( original.realp ) + sqr ( original.imag );     
  2268.       inc ( result );     
  2269.     end;
  2270.   calculate := result;
  2271.  
  2272. end;
  2273.  
  2274.      This function is performed for each pixel in the screen.  In
  2275. a 320 x 200 graphic screen  there are 64000 calls to this function. 
  2276. In a large graphics screen such as 1024 x 768, there would  be
  2277. 786,432 calls to the function.
  2278.  
  2279.      One parameter in the equation not yet examined is ncomplex. 
  2280. Ncomplex is a complex  number which represents the actual pixel on
  2281. the graphics screen. Ncomplex is calculated by  adding the distance
  2282. the pixel is from the corner of the screen
  2283.  
  2284.           ncomplex.realp := current_column_pixel * gap1 +
  2285.                               bcorner.realp;           
  2286.           ncomplex.imag  := current_row_pixel * gap2 +
  2287.                               bcorner.imag;
  2288.  
  2289.      So each pixel starts at the bcorner and adds the number of
  2290. gaps in each direction the pixel  is from the upper left corner,
  2291. thus multiplication by the gaps.
  2292.  
  2293. The entire sequential program appears as
  2294.  
  2295. program mandel;
  2296.  
  2297. {$N+,E+,F+}  (* use 8087 if present or emulate if not *)
  2298.  
  2299. uses dos, crt , graph;
  2300.  
  2301. type
  2302.  
  2303.   complex = record
  2304.           realp : extended;
  2305.           imag  : extended;
  2306.     end;
  2307.  
  2308. var
  2309.  
  2310.   bcorner,
  2311.   ncomplex   : complex;
  2312.   ccol,
  2313.   crow,
  2314.   row,
  2315.   column,
  2316.   result       : integer;
  2317.   gap1,
  2318.   gap2,
  2319.   side1,
  2320.   side2        : extended;
  2321.  
  2322. procedure get_coordinates;
  2323.  
  2324. begin
  2325.  
  2326.   clrscr;
  2327.   write ( 'Enter the real part of the lower left corner ( -2.0 )
  2328. :');     readln ( bcorner.realp );
  2329.   write ( 'Enter the imaginary part of the lower left corner (
  2330. -1.25 ) :');     readln ( bcorner.imag );
  2331.   write ( 'Enter the length of real edge  ( 2.50 ) :'); 
  2332.     readln ( side1 );
  2333.   write ( 'Enter the length of imaginary edge ( 2.50 ) :');    
  2334. readln ( side2 );
  2335.   write ( 'Enter the pixels length of a row ( 320 ) :');
  2336.     readln ( row );
  2337.   write ( 'Enter the pixels length of a column ( 200 ) :');    
  2338. readln ( column );
  2339.  
  2340. end;
  2341.  
  2342. procedure compute_stuff;
  2343.  
  2344. begin
  2345.  
  2346.   gap1 := side1 / row;
  2347.   gap2 := side2 / column;
  2348.  
  2349. end;
  2350.  
  2351. procedure prepare_screen;
  2352.  
  2353. var
  2354.  
  2355.   graphdriver,
  2356.   graphmode      : integer;
  2357.  
  2358.  
  2359. begin
  2360.   graphdriver := vga;
  2361.   graphmode   := vgahi;
  2362.   initgraph ( graphdriver , graphmode , 'c:\tp' );
  2363.  
  2364. end;
  2365.  
  2366. procedure plot ( crow , ccol , result : integer );
  2367.  
  2368. var
  2369.   color : word;
  2370.  
  2371. begin
  2372.  
  2373.   color := 1;
  2374.  
  2375.   if result < 2 then color := 1;
  2376.   if result > 2 then color := 9;
  2377.   if result > 4 then color := 2;
  2378.   if result > 6 then color := 10;
  2379.   if result > 8 then color := 4;
  2380.   if result > 10 then color := 12;
  2381.   if result > 12 then color := 5;
  2382.   if result > 14 then color := 13;
  2383.   if result > 16 then color := 8;
  2384.   if result > 18 then color := 7;
  2385.   if result > 20 then color := 0;
  2386.   putpixel ( ccol , crow , color );
  2387.  
  2388. end;
  2389.  
  2390. procedure get_complex;
  2391.  
  2392. begin
  2393.  
  2394.   ncomplex.realp := ccol * gap1 + bcorner.realp;
  2395.   ncomplex.imag  := crow * gap2 + bcorner.imag;
  2396.  
  2397. end;
  2398.  
  2399. procedure calculate_mandel;
  2400.  
  2401. var
  2402.  
  2403.   original : complex;
  2404.   size     : extended;
  2405.  
  2406. begin
  2407.  
  2408.   result := 0;
  2409.   original.realp := 0.0;
  2410.   original.imag  := 0.0;
  2411.  
  2412.   while ( result <= 21 ) and ( size < 4.0 ) do
  2413.     begin
  2414.       original.realp := original.realp*original.realp -
  2415.           orginal.imag*original.imag + ncomplex.realp;
  2416.       original.imag  := 2 * ( original.realp * original.imag )  +
  2417.           ncomplex.imag;       
  2418.       size := original.realp * original.realp + original.imag  *
  2419.           original.imag;
  2420.       inc ( result );
  2421.     end;
  2422.  
  2423. end;
  2424.  
  2425. begin
  2426.  
  2427.   get_coordinates;
  2428.   prepare_screen;
  2429.   compute_stuff;
  2430.   for ccol := 1 to row do
  2431.     for crow := 1 to column do
  2432.       begin
  2433.         get_complex ( crow , ccol , gap1 , ncomplex , bcorner );  
  2434.       calculate_mandel ( ncomplex , result );
  2435.         plot ( crow , ccol , result );
  2436.       end;
  2437. end.
  2438.  
  2439.      This program can be compiled using Turbo Pascal 5.5 or 6.0 and
  2440. executed to demonstrate  the picture that will be produced.  The
  2441. row and column entries can be increased to 640 by 480 if  desired.
  2442.  
  2443.  
  2444. Parallel Programming Methods
  2445.  
  2446.      The mandelbrot program represents a large number of tasks
  2447. which perform the same operations on a large set of data.  Each and
  2448. every pixel in the graphics screen  has to be calculation on using
  2449. the calculate function presented above.  There is no way around it. 
  2450.  Thus if we have two processor available for work, we can be doing
  2451. two pixels at an given moment instead of just one.  Just think, if
  2452. we had 64000 processors, all  pixels would be calculated at the
  2453. same time.  Think about the speed up.  
  2454.  
  2455.      Our job is to write a parallel program using PCS-Linda and
  2456. Turbo Pascal that will  perform the mandelbrot program using any
  2457. given number of processors.  
  2458.  
  2459.  
  2460. Developer
  2461.  
  2462.      The easiest way to approach this problem is to first consider
  2463. the job or duties of the developer.  After we have determined the
  2464. job of the developer, we can look at  the code the worker will
  2465. execute.  Recall from above that the calculations for each pixel
  2466. all rely  on a set of simple calculations which were performed only
  2467. once.  These include
  2468.  
  2469.           number of pixels in each column
  2470.           number of pixels in each row
  2471.           length of column
  2472.           length of row
  2473.           gap value for column
  2474.           gap value for row
  2475.           corner value
  2476.           column to compute
  2477.           number of columns to compute
  2478. In addition, the graphics screen of the system must also be
  2479. initialized.  
  2480.  
  2481.  
  2482. Columns
  2483.  
  2484.      We must ask a question about how to distribute the work to the
  2485. workers.  The sequential  program computed pixels one at a time. 
  2486. Each pixel is then plotted on the screen.  We could allow  each
  2487. worker to only compute one pixel at a time.  Because of the nature
  2488. of the Parallel Lan  System, there would be some communication
  2489. overhead for each pixel.  In reality it might take  longer for a
  2490. number of processors to compute the screen than it would for a
  2491. single processor if we  only allow each worker to compute one
  2492. pixel. 
  2493.  
  2494.      A solution to this problem may be to allow each worker to
  2495. compute an entire column of  pixels.  This would significantly cut
  2496. down on the communication because there would only be  one exchange
  2497. for every 200 pixels if our example problem.  This is a much better
  2498. solution.  By allowing each  worker to computer a column of pixels,
  2499. we can introduce another  value that will tell each worker how many
  2500. columns to compute.  We might run tests to determine  if each
  2501. worker should have one column, two, four, or more between
  2502. communication calls.
  2503.  
  2504.  
  2505. Results
  2506.  
  2507.      The developer is responsible for setting up the calculations
  2508. as well as receiving the results.   As each worker finishes its
  2509. column or columns, it will have to put the results into the tuple
  2510. space  for the developer to access.  Once the developer has a set
  2511. of results, it can pass to them to a procedure to be plotted. 
  2512. After 320 result packets have been  received, the developer can
  2513. perform any housecleaning necessary and quit execution.
  2514.  
  2515. The code for the developer looks like this
  2516. procedure plot ( col : integer; results : resu );
  2517.  
  2518. var i,j   : integer;
  2519.     color : word;
  2520.  
  2521. begin
  2522.  
  2523.  
  2524. for j := 0 to num_col-1 do
  2525.   for i := 1 to 200 do
  2526.     begin
  2527.       if results[i+j*200] < 20 then color := 1;
  2528.       if results[i+j*200] > 20 then color := 9;
  2529.       if results[i+j*200] > 40 then color := 2;
  2530.       if results[i+j*200] > 60 then color := 10;
  2531.       if results[i+j*200] > 80 then color := 4;
  2532.       if results[i+j*200] > 100 then color := 12;
  2533.       if results[i+j*200] > 120 then color := 5;
  2534.       if results[i+j*200] > 140 then color := 13;
  2535.       if results[i+j*200] > 160 then color := 8;
  2536.       if results[i+j*200] > 180 then color := 7;
  2537.       if results[i+j*200] > 200 then color := 0;
  2538.  
  2539.       putpixel ( col+j , i, color );
  2540.     end;
  2541. end;
  2542.  
  2543. begin
  2544.  
  2545.   start_up;
  2546.  
  2547.   graphdriver := vga;
  2548.   graphmode   := vgahi;
  2549.   initgraph ( graphdriver, graphmode, 'a:' );
  2550.  
  2551.   gap1 :=  2.50 / 320;
  2552.   gap2 :=  2.50 / 200;
  2553.   bcorner.realp := -2.0;
  2554.   bcorner.imag  := -1.25;
  2555.  
  2556.   cur_col :=    1;
  2557.   tot_col :=  320;
  2558.   pix_col :=  200;
  2559.   num_col :=    1;
  2560.  
  2561.   for i := 1 to num_proc do
  2562.     begin
  2563.       eval ( 'work', &adder );
  2564.       out ( 'stuff', &gap1, &gap2, &bcorner );
  2565.     end;
  2566.  
  2567.   out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );
  2568.   for i := 1 to tot_col div num_col do
  2569.     begin
  2570.       in ( 'col', start_col, results );
  2571.       plot ( start_col, results );
  2572.     end;
  2573.  
  2574.   readln;
  2575.  
  2576.  
  2577.   { system_shutdown }
  2578.   close_system
  2579.  
  2580.  
  2581. end.
  2582.  
  2583.  
  2584.  
  2585. Analysis
  2586.  
  2587.      The developer starts by calling the startup procedure for
  2588. initialization of the network.   After the network is setup, the
  2589. screen must be changed to graphics mode. 
  2590.  
  2591.                     graphdriver := vga;
  2592.                     graphmode   := vgahi;
  2593.                     initgraph ( graphdriver, graphmode, 'a:' );
  2594.  
  2595.      These Turbo Pascal commands instruct the graphic card in the
  2596. PC to switch to VGA  mode.  The Turbo Pascal BGI file for VGA must
  2597. be on the drive specified in the initgraph  statement.
  2598.  
  2599.      The developer proceeds to establish the constants for the
  2600. program.  Gap1, gap2, and  bcorner are the same as in the
  2601. sequential program.
  2602.  
  2603.                     gap1 := 2.50 / 320;
  2604.                     gap2 := 2.50 / 200;
  2605.                     bcorner.realp := -2.0;
  2606.                     bcorner.imag  := -1.25;
  2607.  
  2608.      The next four statements set up the working environment for
  2609. the workers.  
  2610.  
  2611.                     cur_col := 1;
  2612.                     tot_col := 320;
  2613.                     pix_col := 200;
  2614.                     num_col := 1;
  2615.  
  2616.      Cur_col is the number of the next column that needs to be
  2617. computed.  Tot_col is the total  number of columns that are to be
  2618. computed.  Pix_col is the total number of pixels in each  column. 
  2619. Num_col is the step value or the number of columns each worker is
  2620. suppose to compute.   These values will all be shared by the
  2621. different workers in the system.
  2622.  
  2623.      Once all of the values are computed, the developer is ready to
  2624. put the work and  initialization values in tuple space for the
  2625. workers to pick up.
  2626.  
  2627.                     for i := 1 to num_proc do
  2628.                     begin
  2629.                       eval ( 'work', &adder );                    
  2630.                       out  ( 'stuff', &gap1, &gap2, &bcorner );   
  2631.                     end;
  2632.  
  2633.      Num_proc is the total number of processor on the system or the
  2634. number of processors to  be utilized in the calculations.  The
  2635. common values for the workers is the next tuple put into tuple 
  2636. space.
  2637.  
  2638.           out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );
  2639.  
  2640.   The developer is now free to concentrate on its own activities
  2641. mainly receiving and plotting the  results.
  2642.  
  2643.              for i := 1 to tot_col DIV num_col do                 
  2644.               begin
  2645.                 in ( 'col', start_col, results );
  2646.                 plot ( start_col, results );
  2647.               end;
  2648.  
  2649.      Num_col is used to divide the total number of 'col' tuples to
  2650. receive based on the number  of columns each worker will calculate.
  2651.  
  2652.      The last thing the developer needs to do is clean up the tuple
  2653. space and shutdown the  system
  2654.  
  2655.        in ( 'screen', cur_col, tot_col, pix_col, num_col );       
  2656.        close_system.
  2657.  
  2658.  
  2659. Worker
  2660.  
  2661.      Next we must determine what the duty of the worker is.  The
  2662. worker must IN the common  data from tuple space.  This data would
  2663. include the gaps and corner value.  The worker would  then IN the
  2664. screen information.  It is this information that will determine
  2665. whether or not a column needs to be computed.  If the worker IN the
  2666. tuple and the cur_col to  compute is greater than the tot_col
  2667. value, then the system has successfully computed all columns.   The
  2668. worker ca quit executing this procedure.  If the cur_col is not
  2669. greater than the tot_col value,  it will have to determine how many
  2670. columns to compute and compute them.  The code for the  worker
  2671. looks like this
  2672. procedure adder;
  2673.  
  2674.  
  2675. type
  2676.  
  2677.   complex = record
  2678.     realp,
  2679.     imag   : double;
  2680.   end;
  2681.  
  2682. var
  2683.  
  2684.  
  2685.   plen : integer;
  2686.   pkt  : pointer;
  2687.   a_tuple : tuple_pointer;
  2688.  
  2689.   gap1,gap2,
  2690.   a,b,c,
  2691.   size      : double;
  2692.   bcorner,
  2693.   ncomplex,
  2694.   original  : complex;
  2695.   cur_col,
  2696.   tot_col,
  2697.   pix_col,
  2698.   num_col,
  2699.   cc,
  2700.   row,
  2701.   r,
  2702.   indexc,
  2703.   result,
  2704.   start_col,
  2705.   end_col   : integer;
  2706.   results   : array[1..200*num_col] of integer;
  2707.   finished  : boolean;
  2708.  
  2709. begin
  2710.  
  2711.  
  2712.   in ( 'stuff', gap1, gap2, bcorner );
  2713.  
  2714.   in ( 'screen', cur_col, tot_col, pix_col, num_col );
  2715.   if cur_col > tot_col then
  2716.     begin
  2717.       finished := true;
  2718.     end
  2719.   else
  2720.     begin
  2721.       finished := false;
  2722.       start_col := cur_col;
  2723.       end_col := cur_col + num_col - 1;
  2724.       cur_col := cur_col + num_col;
  2725.     end;
  2726.     
  2727.     out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );     
  2728.  
  2729.   while not finished do
  2730.     begin
  2731.       indexc := 0;
  2732.       for cc := start_col to end_col do
  2733.         begin
  2734.           for r := 1 to pix_col do
  2735.             begin
  2736.               ncomplex.realp := cc * gap1 + bcorner.realp;
  2737.               ncomplex.imag  := r * gap2 + bcorner.imag;
  2738.               result := 0;
  2739.               size := 0.0;
  2740.               original.realp := 0.0;
  2741.               original.imag  := 0.0;
  2742.               while ( result <= 21 ) and ( size < 4.0 ) do
  2743.                 begin
  2744.                   a := original.realp * original.realp;
  2745.                   b := original.realp * original.imag;
  2746.                   c := original.imag  * original.imag;
  2747.                   original.realp := a-c+ncomplex.realp;
  2748.                   original.imag  := b+b+ncomplex.imag;
  2749.                   size :=
  2750. original.realp*original.realp+original.imag*original.imag;        
  2751.           inc ( result );
  2752.                 end;
  2753.               results[indexc+r] := result;
  2754.             end;
  2755.           indexc := indexc+pix_col;
  2756.         end;
  2757.       out ( 'col', &start_col, &results );
  2758.  
  2759.       in ( 'screen', cur_col, tot_col, pix_col, num_col );
  2760.       if cur_col > tot_col then
  2761.         begin
  2762.           finished := true;
  2763.         end
  2764.       else
  2765.         begin
  2766.           start_col := cur_col;
  2767.           end_col := cur_col + num_col-1;
  2768.           cur_col := cur_col + num_col;
  2769.         end;
  2770.  
  2771.       out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );   
  2772.  end;
  2773.  
  2774. end;
  2775.  
  2776.   The worker begins by INing the common information
  2777.  
  2778.                          in ( 'stuff', gap1, gap2, bcorner );
  2779.  
  2780. followed by the screen information
  2781.  
  2782.                          in ( 'screen', cur_col, tot_col, pix_col,
  2783. num_col )
  2784.  
  2785. and determines if there is anything to compute
  2786.  
  2787.                          if cur_col > tot_col then
  2788.         
  2789. if there isn't anything to do, the boolean variable finished will
  2790. be set to true and the compute loop  will not be entered.  If there
  2791. is work to do, the worker will obtain its starting columns and put
  2792. it  into the variable start_col.  The ending columns will be put
  2793. into the variable end_col.  The cur_col will be increased the
  2794. number of columns the worker is  going to compute.  Once all of
  2795. this has bee determined, the screen tuple is put back into tuple 
  2796. space.
  2797.  
  2798.           begin
  2799.             finished := true;
  2800.           end
  2801.         else
  2802.           begin
  2803.             finished := false;
  2804.             start_col := cur_col;
  2805.             end_col := cur_col + num+col - 1;
  2806.             cur_col := cur_col + num+col;
  2807.           end;
  2808.         out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );
  2809.  
  2810.      Notice that in either case of the if statement, the screen
  2811. tuple is put back into the tuple  space.  If this were not done,
  2812. the other workers in the system would block because they could not 
  2813. find the screen tuple.  Therefore, it must be put back into tuple
  2814. space.  
  2815.  
  2816.      In order to simplify the way results are sent back to the
  2817. developer, a single array was used  that includes enough space for
  2818. the total number of pixels a worker computes.  This includes the 
  2819. situation where multiple columns are computed.  The indexc variable
  2820. does the job of coordinating where the results will go in the
  2821. array.  The first column of pixels will  use the locations 1-200
  2822. while the next columns uses the location 201-400, etc.  Indexc is 
  2823. incremented by pix_col for every column computed.
  2824.  
  2825.      Once all columns have been computed for this particular group
  2826. of columns, they are put  into tuple space with the
  2827.  
  2828.                out ( 'col', &start_col, &results );
  2829.  
  2830. command.  The worker will then IN another screen tuple and begin
  2831. again. 
  2832.  
  2833. Complete Code
  2834.  
  2835.   The complete code for the system is 
  2836.  
  2837. program devman;
  2838.  
  2839. {$N+,E+,F+}
  2840.  
  2841. uses dos, crt, both, work, graph;
  2842.  
  2843. const
  2844.   num_colu = 2;
  2845.   num_proc = 1;
  2846.  
  2847. type
  2848.   complex = record
  2849.     realp,
  2850.     imag   : double;
  2851.   end;
  2852.  
  2853.   resu = array[1..200*num_colu] of integer;
  2854.  
  2855.  
  2856. var
  2857.   gap1,
  2858.   gap2             : double;
  2859.   bcorner          : complex;
  2860.  
  2861.   i,
  2862.   j,
  2863.   cur_col,
  2864.   pix_col,
  2865.   start_col,
  2866.   num_col,
  2867.   tot_col          : integer;
  2868.   results          : resu;
  2869.  
  2870.   graphdriver,
  2871.   graphmode        : integer;
  2872.  
  2873.  
  2874.  
  2875. procedure start_up;
  2876.  
  2877. begin
  2878.  
  2879.   exitsave := exitproc;
  2880.   exitproc := @myexit;
  2881.  
  2882.   master[1] := $00;
  2883.   master[2] := $00;
  2884.   master[3] := $C0;
  2885.   master[4] := $05;
  2886.   master[5] := $86;
  2887.   master[6] := $24;
  2888.  
  2889.   init_system;
  2890.  
  2891. end;
  2892.  
  2893.  
  2894. procedure adder;
  2895.  
  2896.  
  2897. type
  2898.  
  2899.   complex = record
  2900.     realp,
  2901.     imag   : double;
  2902.   end;
  2903.  
  2904. var
  2905.   gap1, gap2,
  2906.   a,b,c,
  2907.   size      : double;
  2908.   bcorner,
  2909.   ncomplex,
  2910.   original  : complex;
  2911.   cur_col,
  2912.   tot_col,
  2913.   num_col,
  2914.   pix_col,
  2915.   cc,
  2916.   row,
  2917.   r,
  2918.   indexc,
  2919.   result,
  2920.   start_col,
  2921.   end_col   : integer;
  2922.   results   : array[1..200*num_colu] of integer;
  2923.   finished  : boolean;
  2924.  
  2925. begin
  2926.  
  2927.  
  2928.   in ( 'stuff', gap1, gap2, bcorner );
  2929.  
  2930.   in ( 'screen', cur_col, tot_col, pix_col, num_col );
  2931.   if cur_col > tot_col then
  2932.     begin
  2933.       finished := true;
  2934.     end
  2935.   else
  2936.     begin
  2937.       finished := false;
  2938.       start_col := cur_col;
  2939.       end_col := cur_col + num_col - 1;
  2940.       cur_col := cur_col + num_col;
  2941.     end;
  2942.     out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );
  2943.  
  2944.   while not finished do
  2945.     begin
  2946.       indexc := 0;
  2947.       for cc := start_col to end_col do
  2948.         begin
  2949.           for r := 1 to pix_col do
  2950.             begin
  2951.               ncomplex.realp := cc * gap1 + bcorner.realp;
  2952.               ncomplex.imag  := r * gap2 + bcorner.imag;
  2953.               result := 0;
  2954.               size := 0.0;
  2955.               original.realp := 0.0;
  2956.               original.imag  := 0.0;
  2957.               while ( result <= 21 ) and ( size < 4.0 ) do
  2958.                 begin
  2959.                   a := original.realp * original.realp;
  2960.                   b := original.realp * original.imag;
  2961.                   c := original.imag  * original.imag;
  2962.                   original.realp := a-c+ncomplex.realp;
  2963.                   original.imag  := b+b+ncomplex.imag;
  2964.                   size :=
  2965. original.realp*original.realp+original.imag*original.imag;        
  2966.           inc ( result );
  2967.                 end;
  2968.               results[indexc+r] := result;
  2969.             end;
  2970.           indexc := indexc+pix_col;
  2971.         end;
  2972.       out ( 'col', &start_col, &results );
  2973.  
  2974.       in ( 'screen', cur_col, tot_col, pix_col, num_col );
  2975.       if cur_col > tot_col then
  2976.         begin
  2977.           finished := true;
  2978.         end
  2979.       else
  2980.         begin
  2981.           start_col := cur_col;
  2982.           end_col := cur_col + num_col-1;
  2983.           cur_col := cur_col + num_col;
  2984.         end;
  2985.       out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );   
  2986.  end;
  2987.  
  2988. end;
  2989.  
  2990.  
  2991.  
  2992. procedure plot ( col : integer; results : resu );
  2993.  
  2994. var i,j   : integer;
  2995.     color : word;
  2996.  
  2997. begin
  2998.  
  2999.  
  3000. for j := 0 to num_col-1 do
  3001.   for i := 1 to 200 do
  3002.     begin
  3003.       if results[i+j*200] < 20 then color := 1;
  3004.       if results[i+j*200] > 20 then color := 9;
  3005.       if results[i+j*200] > 40 then color := 2;
  3006.       if results[i+j*200] > 60 then color := 10;
  3007.       if results[i+j*200] > 80 then color := 4;
  3008.       if results[i+j*200] > 100 then color := 12;
  3009.       if results[i+j*200] > 120 then color := 5;
  3010.       if results[i+j*200] > 140 then color := 13;
  3011.       if results[i+j*200] > 160 then color := 8;
  3012.       if results[i+j*200] > 180 then color := 7;
  3013.       if results[i+j*200] > 200 then color := 0;
  3014.  
  3015.       putpixel ( col+j , i, color );
  3016.     end;
  3017.  
  3018. end;
  3019.  
  3020.  
  3021.  
  3022.  
  3023.  
  3024. begin
  3025.  
  3026.   start_up;
  3027.  
  3028.   graphdriver := vga;
  3029.   graphmode   := vgahi;
  3030.   initgraph ( graphdriver, graphmode, 'a:' );
  3031.  
  3032.   gap1 :=  2.50 / 320;
  3033.   gap2 :=  2.50 / 200;
  3034.   bcorner.realp := -2.0;
  3035.   bcorner.imag  := -1.25;
  3036.   cur_col :=    1;
  3037.   tot_col :=  320;
  3038.   pix_col :=  200;
  3039.   num_col := num_colu;
  3040.  
  3041.   for i := 1 to num_proc do
  3042.     begin
  3043.       eval ( 'work', &adder );
  3044.       out ( 'stuff', &gap1, &gap2, &bcorner );
  3045.     end;
  3046.  
  3047.   out ( 'screen', &cur_col, &tot_col, &pix_col, &num_col );
  3048.  
  3049.   for i := 1 to tot_col div num_col do
  3050.     begin
  3051.       in ( 'col', start_col, results );
  3052.       plot ( start_col, results );
  3053.     end;
  3054.  
  3055.   in ( 'screen', cur_col, tot_col, pix_col, num_col );
  3056.  
  3057.   readln;
  3058.  
  3059.  
  3060.   { system_shutdown }
  3061.   close_system
  3062.  
  3063.  
  3064. end.
  3065.  
  3066.      This code is contained on the samples disk provided with the
  3067. system.  Convert it to  standard Turbo Pascal, compile it, and run
  3068. it for an interesting result.  In order to understand what  the
  3069. code is doing exactly, follow the code for a single developer and
  3070. a single worker.  Notice the changes that take place in the screen
  3071. tuple.  This screen tuple is the  main controller of the entire
  3072. program.
  3073.  
  3074.      Once you have the code operational, try changing some of the
  3075. initial values to obtain  different pictures.  The color codes (
  3076. numbers ) used in the plotting routine can also be change to 
  3077. different sequences.  These number were taken directly from those
  3078. in the Turbo Pascal Reference Manual.
  3079.  
  3080.  
  3081.  
  3082.  
  3083.